Documentation Index Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Hono is built for speed. With its lightweight architecture and Web Standard APIs, Hono delivers excellent performance out of the box. However, there are additional strategies you can use to optimize your applications even further.
Hono uses the RegExpRouter by default, which provides excellent performance:
import { Hono } from 'hono'
// The default router is already optimized
const app = new Hono ()
app . get ( '/posts/:id' , ( c ) => c . json ({ id: c . req . param ( 'id' ) }))
app . get ( '/users/:userId/posts/:postId' , ( c ) => {
return c . json ({
userId: c . req . param ( 'userId' ),
postId: c . req . param ( 'postId' )
})
})
Choosing the Right Router
Hono includes multiple routers optimized for different scenarios:
RegExpRouter - Default, fast for most applications
SmartRouter - Automatically chooses the best router
LinearRouter - Simple, good for small apps
PatternRouter - Memory efficient for simple patterns
import { RegExpRouter } from 'hono/router/reg-exp-router'
import { Hono } from 'hono'
const app = new Hono ({ router: new RegExpRouter () })
Minimize Middleware
Only use middleware where needed:
// Good: Apply middleware to specific routes
app . use ( '/api/*' , logger ())
app . use ( '/admin/*' , authMiddleware )
// Avoid: Global middleware when not needed
// app.use('*', someHeavyMiddleware)
Response Optimization
Stream Large Responses
Use streaming for large responses:
import { stream } from 'hono/streaming'
app . get ( '/large-data' , ( c ) => {
return stream ( c , async ( stream ) => {
// Stream data in chunks
for ( let i = 0 ; i < 100 ; i ++ ) {
await stream . write ( `Chunk ${ i } \n ` )
await stream . sleep ( 100 )
}
})
})
Use Compression
Compress responses to reduce bandwidth:
import { Hono } from 'hono'
import { compress } from 'hono/compress'
const app = new Hono ()
// Apply compression middleware
app . use ( '*' , compress ())
app . get ( '/api/data' , ( c ) => {
const largeData = generateLargeData ()
return c . json ( largeData )
})
Cache Responses
Implement caching for frequently accessed data:
import { cache } from 'hono/cache'
// Cache for 1 hour
app . get (
'/api/posts' ,
cache ({
cacheName: 'posts-cache' ,
cacheControl: 'max-age=3600' ,
})
)
app . get ( '/api/posts' , async ( c ) => {
const posts = await db . posts . findMany ()
return c . json ( posts )
})
Use c.json() Efficiently
The c.json() method is optimized for performance:
app . get ( '/users' , async ( c ) => {
const users = await db . users . findMany ()
return c . json ( users ) // Fast JSON serialization
})
Avoid Unnecessary Serialization
If you already have JSON, use c.text() with appropriate headers:
app . get ( '/data' , async ( c ) => {
const jsonString = await redis . get ( 'cached-data' )
return c . text ( jsonString , 200 , {
'Content-Type' : 'application/json' ,
})
})
Database Optimization
Connection Pooling
Reuse database connections:
import { Hono } from 'hono'
import { createPool } from 'some-db-library'
const pool = createPool ({
max: 10 ,
connectionString: 'postgresql://...' ,
})
const app = new Hono ()
app . get ( '/users' , async ( c ) => {
const client = await pool . connect ()
try {
const result = await client . query ( 'SELECT * FROM users' )
return c . json ( result . rows )
} finally {
client . release ()
}
})
Query Optimization
Fetch only what you need:
// Good: Select specific fields
app . get ( '/users' , async ( c ) => {
const users = await db . users . findMany ({
select: { id: true , name: true , email: true }
})
return c . json ( users )
})
// Avoid: Fetching all fields when unnecessary
// const users = await db.users.findMany()
Use Indexes
Ensure your database queries use indexes:
app . get ( '/users/:id' , async ( c ) => {
const id = c . req . param ( 'id' )
// Make sure 'id' field is indexed
const user = await db . users . findUnique ({ where: { id } })
return c . json ( user )
})
Async Operations
Parallel Requests
Use Promise.all() for parallel operations:
app . get ( '/dashboard' , async ( c ) => {
// Run queries in parallel
const [ users , posts , comments ] = await Promise . all ([
db . users . count (),
db . posts . count (),
db . comments . count (),
])
return c . json ({ users , posts , comments })
})
Background Tasks
Offload heavy tasks using waitUntil:
app . post ( '/events' , async ( c ) => {
const event = await c . req . json ()
// Respond quickly
const response = c . json ({ received: true })
// Process in background (Cloudflare Workers)
c . executionCtx . waitUntil (
processEventAsync ( event )
)
return response
})
Memory Management
Avoid Memory Leaks
Don’t store large objects in global scope:
// Avoid: Global cache that grows indefinitely
// const cache = {}
// Good: Use external cache with TTL
import { LRUCache } from 'lru-cache'
const cache = new LRUCache ({
max: 100 ,
ttl: 1000 * 60 * 5 , // 5 minutes
})
app . get ( '/data/:id' , async ( c ) => {
const id = c . req . param ( 'id' )
if ( cache . has ( id )) {
return c . json ( cache . get ( id ))
}
const data = await fetchData ( id )
cache . set ( id , data )
return c . json ( data )
})
Static Assets
Use CDN for Static Files
Serve static files from a CDN when possible:
import { serveStatic } from 'hono/cloudflare-workers'
app . use ( '/static/*' , serveStatic ({ root: './' }))
app . get ( '/static/*' , serveStatic ({
root: './' ,
onNotFound : ( path , c ) => {
return c . text ( ` ${ path } not found` , 404 )
},
}))
// Add cache headers
app . use ( '/static/*' , async ( c , next ) => {
await next ()
c . header ( 'Cache-Control' , 'public, max-age=31536000' ) // 1 year
})
Bundle Size
Use hono/tiny
For ultra-small bundle size, use the tiny preset:
import { Hono } from 'hono/tiny'
const app = new Hono ()
app . get ( '/' , ( c ) => c . text ( 'Minimal bundle!' ))
export default app
Tree Shaking
Import only what you need:
// Good: Import specific utilities
import { getCookie } from 'hono/cookie'
import { cors } from 'hono/cors'
// Avoid: Importing everything
// import * as hono from 'hono'
Benchmarking
Measure your application’s performance:
import { Hono } from 'hono'
import { timing } from 'hono/timing'
const app = new Hono ()
app . use ( '*' , timing ())
app . get ( '/api/data' , async ( c ) => {
const data = await fetchData ()
return c . json ( data )
})
// Check Server-Timing header in response
Cloudflare Workers
// Use KV for fast edge caching
app . get ( '/cached/:key' , async ( c ) => {
const key = c . req . param ( 'key' )
const cached = await c . env . KV . get ( key )
if ( cached ) {
return c . json ( JSON . parse ( cached ))
}
const data = await fetchData ( key )
await c . env . KV . put ( key , JSON . stringify ( data ), {
expirationTtl: 300 // 5 minutes
})
return c . json ( data )
})
Deno Deploy
// Leverage Deno's native performance
import { Hono } from 'hono'
const app = new Hono ()
app . get ( '/' , ( c ) => c . text ( 'Fast on Deno!' ))
Deno . serve ( app . fetch )
Bun
// Use Bun's fast runtime
import { Hono } from 'hono'
const app = new Hono ()
app . get ( '/' , ( c ) => c . text ( 'Blazing fast with Bun!' ))
export default {
port: 3000 ,
fetch: app . fetch ,
}
Best Practices
Profile before optimizing
Measure performance to identify bottlenecks before making optimizations.
Use caching strategically
Cache responses and data that are frequently accessed but rarely change.
Optimize database queries
Use indexes, limit result sets, and fetch only needed fields.
Deploy to edge platforms like Cloudflare Workers for faster response times.
Minimize middleware overhead
Only apply middleware to routes that need it.