| 1 | # bhvr đĻĢ |
| 2 | |
| 3 |  |
| 4 | |
| 5 | A full-stack TypeScript monorepo starter with shared types, using Bun, Hono, Vite, and React. |
| 6 | |
| 7 | ## Why bhvr? |
| 8 | |
| 9 | While there are plenty of existing app building stacks out there, many of them are either bloated, outdated, or have too much of a vendor lock-in. bhvr is built with the opinion that you should be able to deploy your client or server in any environment while also keeping type safety. |
| 10 | |
| 11 | ## Quickstart |
| 12 | |
| 13 | Make sure [bun](https://bun.sh) is installed |
| 14 | |
| 15 | ```bash |
| 16 | bun --version |
| 17 | ``` |
| 18 | |
| 19 | Run the command below to make a new bhvr project |
| 20 | |
| 21 | ```bash |
| 22 | bun create bhvr@latest my-app |
| 23 | ``` |
| 24 | |
| 25 | Once complete run the dev server |
| 26 | |
| 27 | ```bash |
| 28 | cd my-app |
| 29 | bun dev |
| 30 | ``` |
| 31 | |
| 32 | > [!NOTE] |
| 33 | > Visit [bhvr.dev](https://bhvr.dev) for the full documentation! |
| 34 | |
| 35 | ## Features |
| 36 | |
| 37 | - **Full-Stack TypeScript**: End-to-end type safety between client and server |
| 38 | - **Shared Types**: Common type definitions shared between client and server |
| 39 | - **Monorepo Structure**: Organized as a workspaces-based monorepo with Turbo for build orchestration |
| 40 | - **Modern Stack**: |
| 41 | - [Bun](https://bun.sh) as the JavaScript runtime and package manager |
| 42 | - [Hono](https://hono.dev) as the backend framework |
| 43 | - [Vite](https://vitejs.dev) for frontend bundling |
| 44 | - [React](https://react.dev) for the frontend UI |
| 45 | - [Turbo](https://turbo.build) for monorepo build orchestration and caching |
| 46 | |
| 47 | ## Project Structure |
| 48 | |
| 49 | ``` |
| 50 | . |
| 51 | âââ client/ # React frontend |
| 52 | âââ server/ # Hono backend |
| 53 | âââ shared/ # Shared TypeScript definitions |
| 54 | â âââ src/types/ # Type definitions used by both client and server |
| 55 | âââ package.json # Root package.json with workspaces |
| 56 | âââ turbo.json # Turbo configuration for build orchestration |
| 57 | ``` |
| 58 | |
| 59 | ### Server |
| 60 | |
| 61 | bhvr uses Hono as a backend API for its simplicity and massive ecosystem of plugins. If you have ever used Express then it might feel familiar. Declaring routes and returning data is easy. |
| 62 | |
| 63 | ``` |
| 64 | server |
| 65 | âââ bun.lock |
| 66 | âââ package.json |
| 67 | âââ README.md |
| 68 | âââ src |
| 69 | â  âââ index.ts |
| 70 | âââ tsconfig.json |
| 71 | ``` |
| 72 | |
| 73 | ```typescript src/index.ts |
| 74 | import { Hono } from 'hono' |
| 75 | import { cors } from 'hono/cors' |
| 76 | import type { ApiResponse } from 'shared' |
| 77 | |
| 78 | const app = new Hono() |
| 79 | |
| 80 | app.use(cors()) |
| 81 | |
| 82 | app.get('/', (c) => { |
| 83 | return c.text('Hello Hono!') |
| 84 | }) |
| 85 | |
| 86 | app.get('/hello', async (c) => { |
| 87 | |
| 88 | const data: ApiResponse = { |
| 89 | message: "Hello BHVR!", |
| 90 | success: true |
| 91 | } |
| 92 | |
| 93 | return c.json(data, { status: 200 }) |
| 94 | }) |
| 95 | |
| 96 | export default app |
| 97 | ``` |
| 98 | |
| 99 | If you wanted to add a database to Hono you can do so with a multitude of Typescript libraries like [Supabase](https://supabase.com), or ORMs like [Drizzle](https://orm.drizzle.team/docs/get-started) or [Prisma](https://www.prisma.io/orm) |
| 100 | |
| 101 | ### Client |
| 102 | |
| 103 | bhvr uses Vite + React Typescript template, which means you can build your frontend just as you would with any other React app. This makes it flexible to add UI components like [shadcn/ui](https://ui.shadcn.com) or routing using [React Router](https://reactrouter.com/start/declarative/installation). |
| 104 | |
| 105 | ``` |
| 106 | client |
| 107 | âââ eslint.config.js |
| 108 | âââ index.html |
| 109 | âââ package.json |
| 110 | âââ public |
| 111 | â  âââ vite.svg |
| 112 | âââ README.md |
| 113 | âââ src |
| 114 | â  âââ App.css |
| 115 | â  âââ App.tsx |
| 116 | â  âââ assets |
| 117 | â  âââ index.css |
| 118 | â  âââ main.tsx |
| 119 | â  âââ vite-env.d.ts |
| 120 | âââ tsconfig.app.json |
| 121 | âââ tsconfig.json |
| 122 | âââ tsconfig.node.json |
| 123 | âââ vite.config.ts |
| 124 | ``` |
| 125 | |
| 126 | ```typescript src/App.tsx |
| 127 | import { useState } from 'react' |
| 128 | import beaver from './assets/beaver.svg' |
| 129 | import { ApiResponse } from 'shared' |
| 130 | import './App.css' |
| 131 | |
| 132 | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000" |
| 133 | |
| 134 | function App() { |
| 135 | const [data, setData] = useState<ApiResponse | undefined>() |
| 136 | |
| 137 | async function sendRequest() { |
| 138 | try { |
| 139 | const req = await fetch(`${SERVER_URL}/hello`) |
| 140 | const res: ApiResponse = await req.json() |
| 141 | setData(res) |
| 142 | } catch (error) { |
| 143 | console.log(error) |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | return ( |
| 148 | <> |
| 149 | <div> |
| 150 | <a href="https://github.com/stevedylandev/bhvr" target="_blank"> |
| 151 | <img src={beaver} className="logo" alt="beaver logo" /> |
| 152 | </a> |
| 153 | </div> |
| 154 | <h1>bhvr</h1> |
| 155 | <h2>Bun + Hono + Vite + React</h2> |
| 156 | <p>A typesafe fullstack monorepo</p> |
| 157 | <div className="card"> |
| 158 | <button onClick={sendRequest}> |
| 159 | Call API |
| 160 | </button> |
| 161 | {data && ( |
| 162 | <pre className='response'> |
| 163 | <code> |
| 164 | Message: {data.message} <br /> |
| 165 | Success: {data.success.toString()} |
| 166 | </code> |
| 167 | </pre> |
| 168 | )} |
| 169 | </div> |
| 170 | <p className="read-the-docs"> |
| 171 | Click the beaver to learn more |
| 172 | </p> |
| 173 | </> |
| 174 | ) |
| 175 | } |
| 176 | |
| 177 | export default App |
| 178 | ``` |
| 179 | |
| 180 | ### Shared |
| 181 | |
| 182 | The Shared package is used for anything you want to share between the Server and Client. This could be types or libraries that you use in both environments. |
| 183 | |
| 184 | ``` |
| 185 | shared |
| 186 | âââ package.json |
| 187 | âââ src |
| 188 | â  âââ index.ts |
| 189 | â  âââ types |
| 190 | â  âââ index.ts |
| 191 | âââ tsconfig.json |
| 192 | ``` |
| 193 | |
| 194 | Inside the `src/index.ts` we export any of our code from the folders so it's usable in other parts of the monorepo |
| 195 | |
| 196 | ```typescript |
| 197 | export * from "./types" |
| 198 | ``` |
| 199 | |
| 200 | By running `bun run dev` or `bun run build` it will compile and export the packages from `shared` so it can be used in either `client` or `server` |
| 201 | |
| 202 | ```typescript |
| 203 | import { ApiResponse } from 'shared' |
| 204 | ``` |
| 205 | |
| 206 | ## Getting Started |
| 207 | |
| 208 | ### Quick Start |
| 209 | |
| 210 | You can start a new bhvr project using the [CLI](https://github.com/stevedylandev/create-bhvr) |
| 211 | |
| 212 | ```bash |
| 213 | bun create bhvr |
| 214 | ``` |
| 215 | |
| 216 | ### Installation |
| 217 | |
| 218 | ```bash |
| 219 | # Install dependencies for all workspaces |
| 220 | bun install |
| 221 | ``` |
| 222 | |
| 223 | ### Development |
| 224 | |
| 225 | ```bash |
| 226 | # Run all workspaces in development mode with Turbo |
| 227 | bun run dev |
| 228 | |
| 229 | # Or run individual workspaces directly |
| 230 | bun run dev:client # Run the Vite dev server for React |
| 231 | bun run dev:server # Run the Hono backend |
| 232 | ``` |
| 233 | |
| 234 | ### Building |
| 235 | |
| 236 | ```bash |
| 237 | # Build all workspaces with Turbo |
| 238 | bun run build |
| 239 | |
| 240 | # Or build individual workspaces directly |
| 241 | bun run build:client # Build the React frontend |
| 242 | bun run build:server # Build the Hono backend |
| 243 | ``` |
| 244 | |
| 245 | ### Additional Commands |
| 246 | |
| 247 | ```bash |
| 248 | # Lint all workspaces |
| 249 | bun run lint |
| 250 | |
| 251 | # Type check all workspaces |
| 252 | bun run type-check |
| 253 | |
| 254 | # Run tests across all workspaces |
| 255 | bun run test |
| 256 | ``` |
| 257 | |
| 258 | ### Deployment |
| 259 | |
| 260 | Deplying each piece is very versatile and can be done numerous ways, and exploration into automating these will happen at a later date. Here are some references in the meantime. |
| 261 | |
| 262 | **Client** |
| 263 | - [Orbiter](https://bhvr.dev/deployment/client/orbiter) |
| 264 | - [GitHub Pages](https://bhvr.dev/deployment/client/github-pages) |
| 265 | - [Netlify](https://bhvr.dev/deployment/client/netlify) |
| 266 | - [Cloudflare Pages](https://bhvr.dev/deployment/client/cloudflare-pages) |
| 267 | |
| 268 | **Server** |
| 269 | - [Orbiter](https://bhvr.dev/deployment/server/orbiter) |
| 270 | - [Cloudflare Worker](https://bhvr.dev/deployment/server/cloudflare-workers) |
| 271 | - [Bun](https://bhvr.dev/deployment/server/railway) |
| 272 | - [Node.js](https://bhvr.dev/deployment/server/railway) |
| 273 | |
| 274 | ## Type Sharing |
| 275 | |
| 276 | Types are automatically shared between the client and server thanks to the shared package and TypeScript path aliases. You can import them in your code using: |
| 277 | |
| 278 | ```typescript |
| 279 | import { ApiResponse } from 'shared/types'; |
| 280 | ``` |
| 281 | |
| 282 | ## Learn More |
| 283 | |
| 284 | - [bhvr Documentation](https://bhvr.dev) |
| 285 | - [Bun Documentation](https://bun.sh/docs) |
| 286 | - [Vite Documentation](https://vitejs.dev/guide/) |
| 287 | - [React Documentation](https://react.dev/learn) |
| 288 | - [Hono Documentation](https://hono.dev/docs) |
| 289 | - [Turbo Documentation](https://turbo.build/docs) |
| 290 | - [TypeScript Documentation](https://www.typescriptlang.org/docs/) |