Get started
bhvr is a framework used to build apps that are not tied down to a single provider, and each piece can be deployed in multiple places.
Quickstart
Create a New Project
To start using bhvr make sure you have Bun installed first, then run the following command.
bun create bhvr@latest
The stack is composed of the following:
.
├── client/ # React frontend
├── server/ # Hono backend
├── shared/ # Shared TypeScript definitions
│ └── src/types/ # Type definitions used by both client and server
└── package.json # Root package.json with workspaces
Start Up Dev Server
Once you have created your project you can cd
into it and run the dev server
bun run dev
This will spin up dev servers for the server
, client
, and shared
packages
Try updating the API endpoints in the server
package
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import type { ApiResponse } from 'shared/dist'
const app = new Hono()
app.use(cors())
app.get('/', (c) => {
return c.text('Hello Hono!')
})
app.get('/hello', async (c) => {
const data: ApiResponse = {
message: "Hello BHVR!",
success: true
}
return c.json(data, { status: 200 })
})
export default app
Also try editing the React app in client
import { useState } from 'react'
import beaver from './assets/beaver.svg'
import { ApiResponse } from 'shared'
import './App.css'
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"
function App() {
const [data, setData] = useState<ApiResponse | undefined>()
async function sendRequest() {
try {
const req = await fetch(`${SERVER_URL}/hello`)
const res: ApiResponse = await req.json()
setData(res)
} catch (error) {
console.log(error)
}
}
return (
<>
<div>
<a href="https://github.com/stevedylandev/bhvr" target="_blank">
<img src={beaver} className="logo" alt="beaver logo" />
</a>
</div>
<h1>bhvr</h1>
<h2>Bun + Hono + Vite + React</h2>
<p>A typesafe fullstack monorepo</p>
<div className="card">
<button onClick={sendRequest}>
Call API
</button>
{data && (
<pre className='response'>
<code>
Message: {data.message} <br />
Success: {data.success.toString()}
</code>
</pre>
)}
</div>
<p className="read-the-docs">
Click the beaver to learn more
</p>
</>
)
}
export default App
Build Project
Once you have your project ready to go you can use the build command to build the client
and shared
packages
bun run build
From there you can select multiple deployment options
Manual Setup
There are few other ways you can get started with bhvr outside of the CLI
Clone or Use GitHub Template
If you visit the bhvr repo you can click the "Use This Template" button in the top right.
Alternatively you can clone the template
git clone https://github.com/stevedylandev/bhvr
Create from Scratch
To recreate bhvr from scratch you can do the following
Install Bun
curl -fsSL https://bun.sh/install | bash
Setup Project
mkdir bhvr
cd bhvr
bun init -y
rm index.ts
mkdir shared
Update Root Files
Update tsconfig.json
with the following settings
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Path resolution
"baseUrl": "./",
"paths": {
"@server/*": ["./server/src/*"],
"@client/*": ["./client/src/*"],
"@shared/*": ["./shared/src/*"]
},
// Module resolution
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"verbatimModuleSyntax": true,
// Strictness and best practices
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"experimentalDecorators": true,
// Output control
"skipLibCheck": true,
// Optional strict flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}
Update the package.json
with the following contents
{
"name": "bhvr",
"version": "0.3.0",
"description": "A monorepo template built with Bun, Hono, Vite, and React",
"license": "MIT",
"workspaces": [
"./server",
"./client",
"./shared"
],
"scripts": {
"dev:client": "cd client && bun run dev",
"dev:server": "cd server && bun run dev",
"dev:shared": "cd shared && bun run dev",
"dev": "concurrently \"bun run dev:shared\" \"bun run dev:server\" \"bun run dev:client\"",
"build:client": "cd client && bun run build",
"build:shared": "cd shared && bun run build",
"build:server": "cd server && bun run build",
"build": "bun run build:shared && bun run build:client",
"postinstall": "bun run build:shared && bun run build:server"
},
"keywords": [
"bun",
"hono",
"react",
"vite",
"monorepo"
],
"devDependencies": {
"bun-types": "latest",
"concurrently": "^9.1.2"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
Setup Client
Setup Vite with your preferences
bun create vite@latest client
cd client
Update the package.json
file
{
"name": "client",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"shared": "workspace:*",
"server": "workspace:*"
},
"devDependencies": {
"@eslint/js": "^9.22.0",
"@types/node": "^22.15.2",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.22.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"typescript": "~5.7.2",
"typescript-eslint": "^8.26.1",
"vite": "^6.3.1"
}
}
Update the tsconfig.json
file
{
"extends": "../tsconfig.json",
"files": [],
"references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.app.json"}]
}
Update the vite.config.ts
file
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@client": path.resolve(__dirname, "./src"),
"@server": path.resolve(__dirname, "../server/src"),
"@shared": path.resolve(__dirname, "../shared/src")
}
}
})
Setup Server
Create server
repo with Hono
bun create hono@latest server
cd server
Update the tsconfig.json
file
{
"extends": "../tsconfig.json",
"compilerOptions": {
// Environment settings
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",
// Types
"types": ["bun-types"],
// Output settings
"declaration": true,
"outDir": "dist",
"noEmit": false,
"emitDecoratorMetadata": true,
// Module resolution
"moduleResolution": "bundler",
"allowImportingTsExtensions": false
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Update the package.json
file
{
"name": "server",
"version": "0.0.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "bun run --hot src/index.ts"
},
"dependencies": {
"hono": "^4.7.7",
"shared": "workspace:*"
},
"devDependencies": {
"@types/bun": "latest"
}
}
Setup Shared
Initialize the directory
cd shared
bun init -y
mkdir src
mv index.ts src/index.ts
Update the tsconfig.json
file
{
"extends": "../tsconfig.json",
"compilerOptions": {
// Environment setup
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
// Output configuration
"declaration": true,
"outDir": "./dist",
"noEmit": false,
// Type checking
"strict": true,
"skipLibCheck": true,
// Additional checks
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.test.ts", "dist"]
}
Update the package.json
file
{
"name": "shared",
"version": "0.0.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"devDependencies": {
"typescript": "^5.2.2"
}
}
Start Up bhvr 🦫
bun install
bun dev