Skip to main content
Node.js is the most popular JavaScript runtime. Hono works seamlessly with Node.js using built-in adapters or standard Web APIs.

Quick Start

Create a new Hono project for Node.js:
npm create hono@latest my-app
Select “nodejs” as your template when prompted.

Installation

Add Hono to your existing Node.js project:
npm install hono
For Node.js v18+, you can use the built-in fetch adapter. For earlier versions, install an adapter:
npm install @hono/node-server

Basic Usage

Using Node.js Adapter

Create your application with the Node.js adapter:
index.ts
import { Hono } from 'hono'
import { serve } from '@hono/node-server'

const app = new Hono()

app.get('/', (c) => c.text('Hello Node.js!'))

app.get('/api/hello', (c) => {
  return c.json({ message: 'Hello from Node.js!' })
})

const port = 3000
console.log(`Server is running on http://localhost:${port}`)

serve({
  fetch: app.fetch,
  port,
})

Using Native Node.js APIs

For Node.js v18.0.0+, you can use native fetch support:
index.ts
import { Hono } from 'hono'
import { createServer } from 'node:http'

const app = new Hono()

app.get('/', (c) => c.text('Hello Node.js!'))

const server = createServer((req, res) => {
  const url = new URL(req.url || '', `http://${req.headers.host}`)
  const request = new Request(url, {
    method: req.method,
    headers: req.headers as HeadersInit,
    body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined,
  })

  app.fetch(request).then((response) => {
    res.statusCode = response.status
    response.headers.forEach((value, key) => {
      res.setHeader(key, value)
    })
    response.body?.pipeTo(new WritableStream({
      write(chunk) {
        res.write(chunk)
      },
      close() {
        res.end()
      },
    }))
  })
})

server.listen(3000, () => {
  console.log('Server is running on http://localhost:3000')
})
Using @hono/node-server is recommended as it handles request/response conversion automatically.

Running Your App

With TypeScript

Using tsx for development:
npx tsx index.ts
Or add to package.json:
package.json
{
  "scripts": {
    "dev": "tsx watch index.ts",
    "start": "node dist/index.js",
    "build": "tsc"
  }
}

With JavaScript

node index.js

Adapter Features

Static Files

Serve static files using the node-server adapter:
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { serveStatic } from '@hono/node-server/serve-static'

const app = new Hono()

app.use('/static/*', serveStatic({ root: './' }))
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))

app.get('/', (c) => c.text('Hello!'))

serve({ fetch: app.fetch, port: 3000 })

Connection Info

Get connection information:
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { getConnInfo } from '@hono/node-server/conninfo'

const app = new Hono()

app.get('/info', (c) => {
  const info = getConnInfo(c)
  return c.json({
    remote: info.remote,
  })
})

serve({ fetch: app.fetch, port: 3000 })

Environment Variables

Load environment variables using dotenv:
npm install dotenv
.env
PORT=3000
API_KEY=your-secret-key
DATABASE_URL=postgres://localhost/mydb
index.ts
import 'dotenv/config'
import { Hono } from 'hono'
import { serve } from '@hono/node-server'

const app = new Hono()

app.get('/config', (c) => {
  return c.json({
    apiKey: process.env.API_KEY,
    dbUrl: process.env.DATABASE_URL,
  })
})

const port = Number(process.env.PORT) || 3000
serve({ fetch: app.fetch, port })

Database Integration

PostgreSQL with Drizzle ORM

npm install drizzle-orm postgres
import { Hono } from 'hono'
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import { serve } from '@hono/node-server'

const client = postgres(process.env.DATABASE_URL!)
const db = drizzle(client)

const app = new Hono()

app.get('/users', async (c) => {
  const users = await db.select().from(usersTable)
  return c.json(users)
})

serve({ fetch: app.fetch, port: 3000 })

MongoDB

npm install mongodb
import { Hono } from 'hono'
import { MongoClient } from 'mongodb'
import { serve } from '@hono/node-server'

const client = new MongoClient(process.env.MONGODB_URI!)
await client.connect()

const db = client.db('myapp')
const app = new Hono()

app.get('/users', async (c) => {
  const users = await db.collection('users').find().toArray()
  return c.json(users)
})

serve({ fetch: app.fetch, port: 3000 })

Middleware

CORS

import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { serve } from '@hono/node-server'

const app = new Hono()

app.use('/*', cors())

app.get('/', (c) => c.text('CORS enabled'))

serve({ fetch: app.fetch, port: 3000 })

Logger

import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { serve } from '@hono/node-server'

const app = new Hono()

app.use('*', logger())

app.get('/', (c) => c.text('Hello!'))

serve({ fetch: app.fetch, port: 3000 })

Testing

Use any Node.js testing framework. Example with Vitest:
npm install -D vitest
index.test.ts
import { describe, it, expect } from 'vitest'
import app from './index'

describe('API Tests', () => {
  it('GET /', async () => {
    const res = await app.request('http://localhost/')
    expect(res.status).toBe(200)
    expect(await res.text()).toBe('Hello Node.js!')
  })

  it('GET /api/hello', async () => {
    const res = await app.request('http://localhost/api/hello')
    expect(res.status).toBe(200)
    const json = await res.json()
    expect(json.message).toBe('Hello from Node.js!')
  })
})
Run tests:
npx vitest

Deployment

VPS/Cloud Server

1

Build your application

npm run build
2

Install dependencies on server

npm install --production
3

Run with PM2

Install PM2:
npm install -g pm2
Start your app:
pm2 start dist/index.js --name my-hono-app
pm2 save
pm2 startup

Docker

Create a Dockerfile:
Dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["node", "dist/index.js"]
Build and run:
docker build -t my-hono-app .
docker run -p 3000:3000 my-hono-app

Heroku

Create a Procfile:
web: node dist/index.js
Deploy:
git push heroku main

Best Practices

Use PM2 or systemd to keep your app running and handle restarts.
Use Node.js cluster module or PM2 cluster mode for better performance.
Implement proper error handling and logging.
TypeScript provides better type safety and developer experience.

Performance Tips

  • Use Node.js v20+ for best performance
  • Enable HTTP/2 with the http2 module
  • Implement caching strategies (Redis, in-memory)
  • Use a reverse proxy (nginx, Caddy) in production
  • Enable gzip/brotli compression

Resources

Node.js Documentation

Official Node.js documentation

@hono/node-server

Node.js adapter for Hono

Build docs developers (and LLMs) love