> 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.

# Hono

The same notes API on [Hono](https://hono.dev): one app, served by Node.js or by AWS Lambda.

- native Hono middlewares (`secureHeaders()`) applied to the Dotpress routes, and a native Hono route (`/health`);
- two entries: `node.ts` with `@hono/node-server`, `lambda.ts` with the main entry of the adapter, which has no Node.js server;
- tests in memory with `adapter.fetch()` (Web `Request` and `Response`), over HTTP, and on simulated API Gateway events.

Source: [`examples/hono`](https://github.com/dotpressjs/dotpress/tree/main/examples/hono).

## Run it

```sh
npx degit dotpressjs/dotpress/examples/hono my-api
cd my-api
npm install
npm run dev
```

```sh
curl -X POST localhost:3000/notes -H 'content-type: application/json' -d '{"text":"Hello"}'
curl localhost:3000/notes
curl localhost:3000/health
```

## The routes

The same routes as the [Fastify example](https://dotpress.dev/examples/fastify.md), unchanged: they do not depend on the server.

```ts file="<root>/../examples/hono/src/routes.ts"
import { createRouter, notFoundError } from '@dotpress/core'
import { z } from 'zod'
import type { NoteStore } from './notes.ts'

const Note = z.object({
  id: z.uuid(),
  text: z.string(),
  createdAt: z.iso.datetime(),
})

/** Dotpress routes: they know nothing about Hono or AWS Lambda. */
export const notesRouter = (store: NoteStore) => {
  const router = createRouter()

  router.defineRoute({
    path: '/notes',
    schema: (z) => ({ response: z.array(Note) }),
    handler: () => store.list(),
  })

  router.defineRoute({
    method: 'post',
    path: '/notes',
    status: 201,
    schema: (z) => ({
      body: z.object({ text: z.string().trim().min(1).max(1000) }),
      response: Note,
    }),
    handler: ({ req }) => store.create(req.body.text),
  })

  router.defineRoute({
    path: '/notes/:id',
    schema: () => ({ response: Note }),
    handler: async ({ req }) =>
      (await store.get(req.params.id)) ?? notFoundError('Note not found'),
  })

  return router
}

```

## The app

The app takes its adapter as a parameter: the options of the adapter are shared, the adapter itself comes from the entry.

```ts file="<root>/../examples/hono/src/app.ts"
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())],
  })

```

## Two entries

```ts file="<root>/../examples/hono/src/node.ts"
// 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())
}

```

```ts file="<root>/../examples/hono/src/lambda.ts"
// The AWS Lambda entry: API Gateway (REST and HTTP APIs), Function URLs and
// Application Load Balancers. The main entry of the adapter has no Node.js
// server: the bundle stays small.
import { honoAdapter } from '@dotpress/adapter-hono'
import { createLambdaHandler } from '@dotpress/adapter-hono/lambda'
import { createNotesApp, honoOptions } from './app.ts'

// The app is created at the first invocation (cold start), then reused by
// the next invocations of the execution environment.
export const handler = createLambdaHandler(() =>
  createNotesApp(honoAdapter(honoOptions))
)

```

`npm run build:lambda` bundles the handler into `dist/lambda.mjs`: about 115 kB gzipped, Hono and Zod included, the smallest of the adapters. See [Choosing an adapter](https://dotpress.dev/adapters/index.md).

## Learn more

- [The Hono adapter](https://dotpress.dev/adapters/hono.md)
- [The AWS Lambda adapter](https://dotpress.dev/adapters/aws-lambda.md)
- [Deployment › AWS Lambda](https://dotpress.dev/deployment/aws-lambda.md)
