For AI agents: the complete documentation index is available at https://dotpress.dev/llms.txt, the full documentation bundle is available at https://dotpress.dev/llms-full.txt, and this page is available as Markdown at https://dotpress.dev/adapters/hono.md.

Hono

@dotpress/adapter-hono runs your app on Hono 4.13 or later, on Node.js and AWS Lambda. Hono 5 is tested against its release candidate.

On Node.js

npm
yarn
pnpm
bun
deno
npm install @dotpress/core @dotpress/adapter-hono hono @hono/node-server zod
import { createApp, defineRoute } from '@dotpress/core'
import { honoAdapter } from '@dotpress/adapter-hono/node'

defineRoute({ path: '/hello', handler: () => ({ message: 'Hello' }) })

const app = await createApp({ adapter: honoAdapter() })
await app.listen(3000)

The @dotpress/adapter-hono/node entry serves the app with @hono/node-server. The main entry, @dotpress/adapter-hono, has no Node.js server: it is the one to use on AWS Lambda, where the bundle stays small.

Options

OptionDescription
appAn existing Hono application. new Hono() by default.
beforeRoutes(app)Registers native middlewares and routes before the Dotpress routes.
afterRoutes(app)Registers native middlewares and routes after the Dotpress routes, before the not-found handler.
bodyLimitMaximum request body size, in bytes. 1 MiB by default.
getIp(c)The client IP address (ctx.req.ip). By default, the address given by the runtime: the socket address on Node.js.

Hono middlewares

The Hono example shares its adapter options between Node.js and AWS Lambda, with a native middleware and a native route:

import type { HonoAdapterOptions } from '@dotpress/adapter-hono'
import { createApp, type HttpAdapter, type Logger } from '@dotpress/core'
import type { Hono } from 'hono'
import { secureHeaders } from 'hono/secure-headers'
import { createNoteStore } from './notes.ts'
import { notesRouter } from './routes.ts'

/** Options of the Hono adapter, the same on Node.js and AWS Lambda. */
export const honoOptions: HonoAdapterOptions<Hono> = {
  // Native Hono middlewares and routes, before the Dotpress routes.
  beforeRoutes: (app) => {
    app.use('*', secureHeaders())
    app.get('/health', (c) => c.json({ status: 'ok' }))
  },
}

/**
 * Creates the app on a Hono adapter: `honoAdapter()` of
 * `@dotpress/adapter-hono/node` in `node.ts`, of `@dotpress/adapter-hono`
 * in `lambda.ts` and the tests.
 */
export const createNotesApp = <TAdapter extends HttpAdapter>(
  adapter: TAdapter,
  options: { logger?: Logger } = {}
) =>
  createApp({
    adapter,
    ...(options.logger && { logger: options.logger }),
    routers: [notesRouter(createNoteStore())],
  })
// The Node.js entry: @hono/node-server serves the app.
import { honoAdapter } from '@dotpress/adapter-hono/node'
import { createNotesApp, honoOptions } from './app.ts'

const port = Number(process.env.PORT ?? 3000)

const app = await createNotesApp(honoAdapter(honoOptions))
await app.listen(port)
console.log(`Notes API: http://localhost:${port}/notes`)

// Waits for pending requests, then runs the onClose hooks of the plugins.
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
  process.once(signal, () => void app.close())
}

Behavior

  • Routes are matched by Dotpress, with the same rules on every adapter: Hono options such as strict do not apply. Use the basePath option of createApp() rather than app.basePath().
  • Bodies are read by the adapter: JSON, forms, text and multipart uploads. A body already read by a native middleware through Hono (c.req.json(), c.req.parseBody()…) is taken from its cache. Routes declared with rawBody: true need the exact bytes: let the adapter read the body, or read it with c.req.arrayBuffer() or c.req.blob() in a native middleware.
  • HTTPException client errors (4xx) thrown by native middlewares use the Dotpress error format and keep their status, message and headers (the WWW-Authenticate header of bearerAuth()…). Other errors are unexpected (500). The adapter takes over app.notFound() and app.onError().
  • ctx.req.ip does not read proxy headers such as X-Forwarded-For: behind a proxy, read them in getIp(c), and only trust the proxies you run.
  • ctx.raw is the Hono context.
  • close() waits for pending requests and closes the responses being streamed; adapter.server() returns the Node.js HTTP server.

Other runtimes

The main entry only relies on Hono and Web-standard APIs. adapter.fetch handles a Web Request, like app.fetch in Hono, for runtimes that take a fetch handler:

import { honoAdapter } from '@dotpress/adapter-hono'

const adapter = honoAdapter()
await createApp({ adapter, routers })

export default { fetch: adapter.fetch }
Warning

Dotpress 2.0 is tested on Node.js and AWS Lambda only: other runtimes (Bun, Deno, edge runtimes) are not officially supported yet. See the design decision.

On AWS Lambda

The same app runs on AWS Lambda with createLambdaHandler() of @dotpress/adapter-hono/lambda: see AWS Lambda.