Bun is a fast all-in-one JavaScript runtime that includes a bundler, test runner, and package manager. Hono works seamlessly with Bun and takes advantage of its performance.
Quick Start
Create a new Hono project for Bun:
Select “bun” as your template when prompted.
Installation
Add Hono to your existing Bun project:
Basic Usage
Create your application in index.ts:
import { Hono } from 'hono'
const app = new Hono ()
app . get ( '/' , ( c ) => c . text ( 'Hello Bun!' ))
app . get ( '/api/hello' , ( c ) => {
return c . json ({ message: 'Hello from Bun!' })
})
export default app
Bun automatically uses the default export as the fetch handler.
Running Your App
Run your Hono app with Bun:
Or use the development mode with hot reload:
Adapter Features
The Bun adapter provides several utilities:
Static Files
Serve static files from a directory:
import { Hono } from 'hono'
import { serveStatic } from 'hono/bun'
const app = new Hono ()
app . use ( '/static/*' , serveStatic ({ root: './' }))
app . use ( '/favicon.ico' , serveStatic ({ path: './favicon.ico' }))
app . get ( '/' , ( c ) => c . text ( 'Hello!' ))
export default app
WebSocket Support
Bun has native WebSocket support. Use Hono’s Bun adapter for WebSockets:
import { Hono } from 'hono'
import { createBunWebSocket } from 'hono/bun'
const app = new Hono ()
const { upgradeWebSocket , websocket } = createBunWebSocket ()
app . get (
'/ws' ,
upgradeWebSocket (( c ) => {
return {
onMessage ( event , ws ) {
console . log ( `Message from client: ${ event . data } ` )
ws . send ( 'Hello from server!' )
},
onClose : () => {
console . log ( 'Connection closed' )
},
}
})
)
// Export with websocket handler
export default {
port: 3000 ,
fetch: app . fetch ,
websocket ,
}
Connection Info
Get connection information including IP address:
import { Hono } from 'hono'
import { getConnInfo } from 'hono/bun'
const app = new Hono ()
app . get ( '/info' , ( c ) => {
const info = getConnInfo ( c )
return c . json ({
remote: info . remote ,
})
})
export default app
Accessing Bun Server
Access the underlying Bun server instance:
import { Hono } from 'hono'
import { getBunServer } from 'hono/bun'
import type { Server } from 'bun'
const app = new Hono ()
app . get ( '/server' , ( c ) => {
const server = getBunServer < Server >( c )
return c . json ({
port: server ?. port ,
hostname: server ?. hostname ,
})
})
export default app
Static Site Generation (SSG)
Generate static files from your Hono app:
import { Hono } from 'hono'
import { toSSG } from 'hono/bun'
const app = new Hono ()
app . get ( '/' , ( c ) => c . html ( '<h1>Home</h1>' ))
app . get ( '/about' , ( c ) => c . html ( '<h1>About</h1>' ))
// Generate static files
toSSG ( app , { dir: './dist' })
Custom Server Configuration
Configure the Bun server with custom options:
import { Hono } from 'hono'
const app = new Hono ()
app . get ( '/' , ( c ) => c . text ( 'Hello!' ))
export default {
port: 3000 ,
hostname: '0.0.0.0' ,
fetch: app . fetch ,
development: process . env . NODE_ENV !== 'production' ,
}
Environment Variables
Bun loads .env files automatically:
API_KEY=your-secret-key
DATABASE_URL=postgres://localhost/mydb
Access environment variables:
import { Hono } from 'hono'
const app = new Hono ()
app . get ( '/config' , ( c ) => {
return c . json ({
apiKey: process . env . API_KEY ,
dbUrl: process . env . DATABASE_URL ,
})
})
export default app
Using Bun APIs
File System
Use Bun’s fast file system APIs:
import { Hono } from 'hono'
const app = new Hono ()
app . get ( '/file/:name' , async ( c ) => {
const name = c . req . param ( 'name' )
const file = Bun . file ( `./files/ ${ name } ` )
if ( ! ( await file . exists ())) {
return c . notFound ()
}
return c . body ( await file . arrayBuffer ())
})
export default app
SQLite
Use Bun’s built-in SQLite:
import { Hono } from 'hono'
import { Database } from 'bun:sqlite'
const app = new Hono ()
const db = new Database ( 'mydb.sqlite' )
app . get ( '/users' , ( c ) => {
const users = db . query ( 'SELECT * FROM users' ). all ()
return c . json ( users )
})
app . post ( '/users' , async ( c ) => {
const body = await c . req . json ()
db . run ( 'INSERT INTO users (name, email) VALUES (?, ?)' , [ body . name , body . email ])
return c . json ({ message: 'User created' })
})
export default app
Testing
Bun includes a built-in test runner:
import { expect , test } from 'bun:test'
import app from './index'
test ( 'GET /' , async () => {
const res = await app . request ( 'http://localhost/' )
expect ( res . status ). toBe ( 200 )
expect ( await res . text ()). toBe ( 'Hello Bun!' )
})
test ( 'GET /api/hello' , async () => {
const res = await app . request ( 'http://localhost/api/hello' )
expect ( res . status ). toBe ( 200 )
const json = await res . json ()
expect ( json . message ). toBe ( 'Hello from Bun!' )
})
Run tests:
Package Scripts
Set up scripts in package.json:
{
"name" : "my-hono-app" ,
"scripts" : {
"dev" : "bun --hot run index.ts" ,
"start" : "bun run index.ts" ,
"test" : "bun test"
},
"dependencies" : {
"hono" : "^4.0.0"
},
"devDependencies" : {
"bun-types" : "latest"
}
}
Run scripts:
bun run dev # Development with hot reload
bun run start # Production
bun test # Run tests
Deployment
Standalone Binary
Build a standalone executable:
bun build --compile --minify --sourcemap ./index.ts --outfile myapp
Run the binary:
Docker
Create a Dockerfile:
FROM oven/bun:1
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
EXPOSE 3000
CMD [ "bun" , "run" , "index.ts" ]
Build and run:
docker build -t my-hono-app .
docker run -p 3000:3000 my-hono-app
VPS/Cloud Deployment
Install Bun on your server
curl -fsSL https://bun.sh/install | bash
Clone and install dependencies
git clone https://github.com/your-username/my-app.git
cd my-app
bun install
Run with process manager
Use PM2 or systemd: pm2 start "bun run index.ts" --name my-hono-app
Best Practices
Use hot reload in development
The --hot flag provides instant feedback during development.
Leverage Bun's built-in APIs
Use Bun.file(), bun:sqlite, and other built-in APIs for better performance.
Bun runs TypeScript natively without a build step.
Bun’s test runner is fast and includes built-in matchers.
Bun is significantly faster than Node.js for I/O operations
Use Bun.file() for file operations instead of fs module
Leverage Bun’s native WebSocket implementation
Use bun:sqlite for embedded databases
Resources
Bun Documentation Official Bun documentation
Bun Runtime APIs Explore Bun’s built-in APIs