Skip to content

Hono Adapter

binja provides a first-class adapter for Hono, the ultra-fast web framework for Bun.

Installation

Terminal window
bun add binja hono

Basic Usage

import { Hono } from 'hono'
import { binja } from 'binja/hono'
const app = new Hono()
// Add binja middleware
app.use(binja({
root: './views',
}))
// Render templates with c.render()
app.get('/', (c) => c.render('index', { title: 'Home' }))
app.get('/users/:id', async (c) => {
const user = await getUser(c.req.param('id'))
return c.render('users/profile', { user })
})
export default app

Configuration Options

app.use(binja({
root: './views', // Template directory
extension: '.html', // Default extension
engine: 'jinja2', // jinja2 | handlebars | liquid | twig
cache: true, // Cache compiled templates
globals: { // Global context
siteName: 'My App',
year: new Date().getFullYear(),
},
layout: 'layouts/base', // Optional layout template
contentVar: 'content', // Content variable name in layout
}))

Options Reference

OptionTypeDefaultDescription
rootstring./viewsTemplate directory
extensionstring.htmlDefault file extension
enginestringjinja2Template engine
cachebooleantrue (prod)Cache compiled templates
debugbooleanfalseShow error details
globalsobject{}Global context variables
layoutstring-Layout template path
contentVarstringcontentContent variable name

Using Layouts

app.use(binja({
root: './views',
layout: 'layouts/base', // Will render layouts/base.html
}))
app.get('/', (c) => c.render('pages/home', { title: 'Home' }))

layouts/base.html

<!DOCTYPE html>
<html>
<head>
<title>{{ title }} | {{ siteName }}</title>
</head>
<body>
{{ content|safe }}
</body>
</html>

pages/home.html

<h1>Welcome to {{ siteName }}!</h1>
<p>This is the home page.</p>

Multi-Engine Support

// Use Handlebars for specific routes
app.use('/admin/*', binja({
root: './admin-views',
engine: 'handlebars',
}))
// Use Liquid for main site
app.use(binja({
root: './views',
engine: 'liquid',
}))

Cache Management

import { clearCache, getCacheStats } from 'binja/hono'
// Clear all cached templates
app.get('/admin/clear-cache', (c) => {
clearCache()
return c.text('Cache cleared')
})
// Get cache statistics
app.get('/admin/cache-stats', (c) => {
const stats = getCacheStats()
return c.json(stats)
// { size: 10, keys: ['jinja2:./views/index.html', ...] }
})

With HTMX

import { Hono } from 'hono'
import { binja } from 'binja/hono'
const app = new Hono()
app.use(binja({ root: './views' }))
// Full page
app.get('/', (c) => c.render('index', { items: [] }))
// HTMX partial
app.post('/items', async (c) => {
const body = await c.req.json()
const item = await createItem(body)
// Render just the item component
return c.render('components/item', { item })
})

Error Handling

app.use(binja({
root: './views',
debug: process.env.NODE_ENV !== 'production',
}))
// Custom error page
app.onError((err, c) => {
return c.render('errors/500', {
error: c.env.debug ? err.message : 'Something went wrong'
})
})
app.notFound((c) => {
return c.render('errors/404')
})