Node.js
Node.js is an open-source, cross-platform JavaScript runtime environment.
Hono was not designed for Node.js at first, but with a Node.js Adapter, it can run on Node.js as well.
INFO
It works on Node.js versions greater than 18.x. The specific required Node.js versions are as follows:
- 18.x => 18.14.1+
- 19.x => 19.7.0+
- 20.x => 20.0.0+
Essentially, you can simply use the latest version of each major release.
1. Setup
A starter for Node.js is available. Start your project with "create-hono" command. Select nodejs template for this example.
npm create hono@latest my-appyarn create hono my-apppnpm create hono my-appbun create hono@latest my-appdeno init --npm hono my-appMove to my-app and install the dependencies.
cd my-app
npm icd my-app
yarncd my-app
pnpm icd my-app
bun i2. Hello World
Edit src/index.ts:
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Node.js!'))
serve(app)If you want to gracefully shut down the server, write it like this:
const server = serve(app)
// graceful shutdown
process.on('SIGINT', () => {
server.close()
process.exit(0)
})
process.on('SIGTERM', () => {
server.close((err) => {
if (err) {
console.error(err)
process.exit(1)
}
process.exit(0)
})
})3. Run
Run the development server locally. Then, access http://localhost:3000 in your Web browser.
npm run devyarn devpnpm devChange port number
You can specify the port number with the port option.
serve({
fetch: app.fetch,
port: 8787,
})Access the raw Node.js APIs
You can access the Node.js APIs from c.env.incoming and c.env.outgoing.
import { Hono } from 'hono'
import { serve, type HttpBindings } from '@hono/node-server'
// or `Http2Bindings` if you use HTTP2
type Bindings = HttpBindings & {
/* ... */
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/', (c) => {
return c.json({
remoteAddress: c.env.incoming.socket.remoteAddress,
})
})
serve(app)Serve static files
You can use serveStatic to serve static files from the local file system. For example, suppose the directory structure is as follows:
./
├── favicon.ico
├── index.ts
└── static
├── hello.txt
└── image.pngIf a request to the path /static/* comes in and you want to return a file under ./static, you can write the following:
import { serveStatic } from '@hono/node-server/serve-static'
app.use('/static/*', serveStatic({ root: './' }))WARNING
The root option resolves paths relative to the current working directory (process.cwd()). This means the behavior depends on where you run your Node.js process from, not where your source file is located. If you start your server from a different directory, file resolution may fail.
For reliable path resolution that always points to the same directory as your source file, use import.meta.url:
import { fileURLToPath } from 'node:url'
import { serveStatic } from '@hono/node-server/serve-static'
app.use(
'/static/*',
serveStatic({ root: fileURLToPath(new URL('./', import.meta.url)) })
)Use the path option to serve favicon.ico in the directory root:
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))If a request to the path /hello.txt or /image.png comes in and you want to return a file named ./static/hello.txt or ./static/image.png, you can use the following:
app.use('*', serveStatic({ root: './static' }))rewriteRequestPath
If you want to map http://localhost:3000/static/* to ./statics, you can use the rewriteRequestPath option:
app.get(
'/static/*',
serveStatic({
root: './',
rewriteRequestPath: (path) =>
path.replace(/^\/static/, '/statics'),
})
)http2
You can run hono on a Node.js http2 Server.
unencrypted http2
import { createServer } from 'node:http2'
const server = serve({
fetch: app.fetch,
createServer,
})encrypted http2
import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'
const server = serve({
fetch: app.fetch,
createServer: createSecureServer,
serverOptions: {
key: readFileSync('localhost-privkey.pem'),
cert: readFileSync('localhost-cert.pem'),
},
})Building & Deployment
npm run buildyarn run buildpnpm run buildbun run buildINFO
Apps with a front-end framework may need to use Hono's Vite plugins.
Dockerfile
Here is an example of a Node.js Dockerfile.
FROM node:22-alpine AS base
FROM base AS builder
RUN apk add --no-cache gcompat
WORKDIR /app
COPY package*json tsconfig.json src ./
RUN npm ci && \
npm run build && \
npm prune --production
FROM base AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 hono
COPY --from=builder --chown=hono:nodejs /app/node_modules /app/node_modules
COPY --from=builder --chown=hono:nodejs /app/dist /app/dist
COPY --from=builder --chown=hono:nodejs /app/package.json /app/package.json
USER hono
EXPOSE 3000
CMD ["node", "/app/dist/index.js"]