Deployment
Production checklist
- Set
NODE_ENV=productionso 5xxdetailis redacted. - Set a sane
bodyLimitBytesper route group (don't default to 1 MiB everywhere). - Set
requestTimeoutMsto less than your load balancer's idle timeout. - Mount
secureHeaders(),requestId(), andrateLimit()globally. - Wire your structured logger and propagate
request-idto downstream calls. - Run contract tests in CI — fail the build if the spec drifts.
- Use
pnpm install --frozen-lockfilein CI; neverpnpm install.
Docker (Node, distroless)
# syntax=docker/dockerfile:1
FROM node:20-bookworm AS deps
WORKDIR /app
RUN corepack enable
COPY package.json pnpm-lock.yaml .npmrc ./
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile --prod
FROM node:20-bookworm AS build
WORKDIR /app
RUN corepack enable
COPY package.json pnpm-lock.yaml .npmrc ./
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM gcr.io/distroless/nodejs20-debian12 AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY package.json ./
USER 1000
EXPOSE 3000
CMD ["dist/server.js"]Graceful shutdown
The Node adapter installs SIGTERM/SIGINT handlers by default. DaloyJS stops accepting new requests (returning 503) and waits up to shutdownTimeoutMs for in-flight requests to drain.
const { close } = serve(app, {
shutdownTimeoutMs: 15_000,
handleSignals: true,
});
// or trigger manually:
await app.shutdown(15_000);Reverse proxy
If you sit behind nginx / Caddy / an LB, set:
X-Forwarded-For/X-Forwarded-Protopropagation for accurate logs.- If you use
rateLimit(), either pass an explicitkeyGeneratoror enabletrustProxyHeaders: trueonly after the proxy strips client-supplied forwarding headers. - Make the LB's idle timeout greater than DaloyJS's
requestTimeoutMs. - Make DaloyJS's
keepAliveTimeoutgreater than the LB's — Node adapter does this for you.
Edge / serverless
DaloyJS can run on Vercel Edge, Cloudflare Workers, and Deno Deploy because the core is Web-standard Request → Response. Vercel is a first-class target; use the scaffolder when starting from scratch:
pnpm create daloy@latest my-api --template vercel-edgeThe Vercel template creates a catch-all api/[...path].ts route and exportstoEdgeHandler(app) from @daloyjs/core/vercel. Cloudflare is only another supported runtime option; you do not need it unless you deploy to Workers.
import { toEdgeHandler } from "@daloyjs/core/vercel";
export const config = { runtime: "edge" };
export default toEdgeHandler(app);See Adapters for runtime-specific entry points.