Search docs

Jump between documentation pages.

Deployment

Production checklist

  • Set NODE_ENV=production so 5xx detail is redacted.
  • Set a sane bodyLimitBytes per route group (don't default to 1 MiB everywhere).
  • Set requestTimeoutMs to less than your load balancer's idle timeout.
  • Mount secureHeaders(), requestId(), and rateLimit() globally.
  • Wire your structured logger and propagate request-id to downstream calls.
  • Run contract tests in CI — fail the build if the spec drifts.
  • Use pnpm install --frozen-lockfile in CI; never pnpm install.

Docker (Node, distroless)

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

ts
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-Proto propagation for accurate logs.
  • If you use rateLimit(), either pass an explicit keyGenerator or enable trustProxyHeaders: true only after the proxy strips client-supplied forwarding headers.
  • Make the LB's idle timeout greater than DaloyJS's requestTimeoutMs.
  • Make DaloyJS's keepAliveTimeout greater 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:

bash
pnpm create daloy@latest my-api --template vercel-edge

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

ts
import { toEdgeHandler } from "@daloyjs/core/vercel";

export const config = { runtime: "edge" };
export default toEdgeHandler(app);

See Adapters for runtime-specific entry points.