recipes / container-images / hono
Containerize a Hono API
A Hono service on the Node.js adapter, built in two stages into a distroless image, with the Bun variant alongside.
Hono is small and runtime-agnostic, which makes its image the simplest case:
the runtime, hono, the adapter, and your code.
Application
// src/server.js
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
app.get("/healthz", (c) => c.text("ok"));
app.get("/", (c) => c.json({ message: "hello" }));
serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000), hostname: "0.0.0.0" });
Dockerfile
# syntax=docker/dockerfile:1
FROM node:24-bookworm-slim AS build
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev
COPY src ./src
FROM gcr.io/distroless/nodejs24-debian12:nonroot
WORKDIR /app
ENV NODE_ENV=production PORT=3000
COPY --from=build --chown=nonroot:nonroot /app/package.json ./
COPY --from=build --chown=nonroot:nonroot /app/node_modules ./node_modules
COPY --from=build --chown=nonroot:nonroot /app/src ./src
EXPOSE 3000
CMD ["src/server.js"]
TypeScript
Compile in the build stage and copy dist/ instead of src/. Do not ship
tsx or ts-node into the runtime stage; startup time and image size both pay
for it, and the distroless image has no room for a compiler anyway.
COPY tsconfig.json ./
COPY src ./src
RUN npm run build && npm prune --omit=dev
# ...
COPY --from=build --chown=nonroot:nonroot /app/dist ./dist
CMD ["dist/server.js"]
Bun
Same app, Bun.serve() instead of the Node.js adapter, and the Bun images:
FROM oven/bun:1 AS build
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --production
COPY src ./src
FROM oven/bun:1-distroless
WORKDIR /app
COPY --from=build --chown=nonroot:nonroot /app ./
USER nonroot
CMD ["src/server.ts"]
Notes
hostname: "0.0.0.0"inserve(). The adapter defaults to all interfaces, but be explicit; Fastify users have been bitten by the opposite default.- Health and readiness routes come before any middleware that needs a database.
- Shutdown handling for Hono is in graceful shutdown with Hono.
See it applied
- examples/frameworks/hono in the repository
- examples/full - every recipe applied to one app
Updated 2026-09-10 · tags: hono, dockerfile, api, distroless, bun · edit on GitHub