Deployment

Dawn is not a managed hosting platform — there's no Dawn-operated cloud you push to. It owns local development (dawn dev, dawn run, dawn test) and the build step that produces deployable artifacts (dawn build). dawn build emits up to two targets, selected via build.targets (default: both):

  • node — a server.mjs entry that boots the real Dawn runtime, plus a hardened Dockerfile. This is the only target that runs Agent Protocol and AG-UI and engages the execution sandbox in production. See Deploying to production (Node/Docker) below.
  • langsmithlanggraph.json plus per-route entry files, for LangSmith or another runtime that consumes the generated LangGraph entry files directly. This target does not run the Dawn runtime and does not engage the sandbox. See The LangSmith / LangGraph Platform path below.

Use live-server scenario tests to catch protocol-shape issues before deploying either target.

Deploying to production (Node/Docker)

dawn build's node target emits a runnable production server, not just a platform artifact:

  • .dawn/build/server.mjs — imports serveRuntime from @dawn-ai/cli and boots the full Dawn runtime on one HTTP listener: Agent Protocol (/threads), AG-UI (/agui/:routeId), and /healthz.
  • Dockerfile — a hardened multi-stage node:22-slim image: runs as non-root 1000:1000, EXPOSE 8000, a HEALTHCHECK against /healthz, CMD ["node", ".dawn/build/server.mjs"]. Written to the app root unless a Dockerfile already exists there, in which case it's written to .dawn/build/Dockerfile instead so an existing Dockerfile is never overwritten.
text
dawn build
docker build -t my-app .
docker run -p 8000:8000 --env-file .env my-app

For local production-like serving without Docker, use dawn start, which boots the same runtime directly:

text
dawn start
dawn start --host 127.0.0.1 --port 3000

--host/--port flags, or HOST/PORT environment variables, override the 0.0.0.0:8000 default — the same bind-everywhere default the generated Dockerfile's HEALTHCHECK assumes.

Because it runs the actual Dawn runtime, this is the only deployment path that engages the execution sandbox, tool scoping, and permissions exactly as configured in dawn.config.ts. The langsmith target does not run the Dawn runtime and does not engage any of the three.

The built runtime and dawn start serve the same Agent Protocol and AG-UI routes as dawn dev; generated server entrypoints call the exported serveRuntime() function directly. In both modes, src/middleware.ts gates Agent Protocol run, wait, and resume execution plus AG-UI route execution, but not thread create, read, delete, or state endpoints. Allowed middleware context reaches tools as ctx.middleware.

Select targets explicitly in dawn.config.ts if you only want one:

dawn.config.ts
import { config } from "@dawn-ai/cli"
 
export default config({
  build: { targets: ["node"] }, // omit "langsmith" if you don't deploy there
})

To run the built image on Kubernetes — as a Deployment + Service with optional Ingress, autoscaling, and a PodDisruptionBudget, wired to the sandbox provider's orchestrator ServiceAccount — see Deploying a Dawn app (Helm), or the orientation section below.

Deploying on Kubernetes

Running the node target's image on a Kubernetes cluster is a two-chart arc, published as OCI artifacts alongside the @dawn-ai/* npm packages:

  • dawn-sandbox-infra — cluster-side infrastructure a kubernetesSandbox deployment needs: namespace, least-privilege RBAC, a default-deny egress NetworkPolicy backstop, ResourceQuota/LimitRange, Pod Security Standard labels, and a PVC reaper. Install this once per cluster or environment, before pointing kubernetesSandbox at it. Full reference: Deploying the sandbox infrastructure.
  • dawn-app — your built node-target image, run as a Deployment + Service with optional Ingress, HorizontalPodAutoscaler, and PodDisruptionBudget, wired to the sandbox infra chart's orchestrator ServiceAccount when your app configures kubernetesSandbox. Full reference: Deploying a Dawn app.

Minimum: a Kubernetes cluster the charts can install into. Recommended: a policy-capable CNI (Calico or Cilium) if you rely on kubernetesSandbox's deny-mode NetworkPolicy as a hard egress boundary — a CNI that ignores NetworkPolicy leaves the Pod's network open regardless of config, which is why dawn check's preflight() warns rather than guarantees enforcement. See Network policy on Kubernetes.

Neither chart builds your image — build it with dawn build's node target first, same as the plain Docker path above, then point dawn-app at the resulting image.repository/image.tag.

The LangSmith / LangGraph Platform path

This path targets LangSmith or another runtime that consumes langgraph.json and the generated per-route entry files directly, instead of running the Dawn runtime. It does not serve AG-UI and does not engage the execution sandbox.

  1. 1

    Verify locally

    text
    dawn verify

    dawn verify runs four checks in one call: app contract, route discovery, typegen, and deps (missing packages and missing env vars). Pass --json for machine-readable output. The deps check is uniquely useful before a deploy — neither dawn check nor dawn typegen covers it.

    Optionally follow with scenario coverage:

    text
    dawn test
  2. 2

    Confirm protocol parity

    Run scenarios against a live dev server by setting run.url per-scenario in your run.test.ts files (the command-level --url flag does not exist on dawn test). dawn dev exposes Agent Protocol endpoints — /threads/:id/runs/wait and /threads/:id/runs/stream — so this catches request/response shape issues before deploy. Process boundaries, state persistence, and tool bindings are still re-materialized by dawn build for production, so this step is necessary but not sufficient.

    text
    dawn dev --port 3001 &
    # In your run.test.ts: set run: { url: "http://127.0.0.1:3001" } per scenario
    dawn test
  3. 3

    Build the deployment artifact

    dawn build writes .dawn/build/langgraph.json along with per-route entry files under .dawn/build/<routeSlug>.ts. For agent routes, the generated entry imports your default agent() descriptor, materializes it as a LangGraph graph, and wires in every discovered route tool.

    text
    dawn build --clean

    A typical generated .dawn/build/langgraph.json looks like:

    json
    {
      "graphs": {
        "/research#agent": "./.dawn/build/research.ts:graph"
      },
      "dependencies": ["."],
      "env": ".env.example",
      "node_version": "22"
    }

    Notes:

    • Each graph key is <routeId>#<kind> — e.g. /research#agent. Use this exact string as the assistant_id in any client request.
    • dependencies: ["."] and node_version: "22" are required by LangSmith.
    • env resolves to .env.example when that file exists, else .env.
    • If you keep a hand-authored langgraph.json at the app root, dawn build shallow-merges it on top of the generated values.
  4. 4

    Local middleware (optional)

    src/middleware.ts (default-exporting a function from defineMiddleware) runs before local /threads/:id/runs/wait and /threads/:id/runs/stream requests handled by dawn dev. Use it to gate access by header, populate request-scoped context, or reject(status, body) unauthorized callers during local development and live-server tests. dawn build does not currently materialize this middleware into the generated LangSmith entry files. See Middleware for the API.

  5. 5

    Push to your LangSmith-connected remote

    LangSmith builds from the generated langgraph.json and route entry files, then provisions assistants keyed by the <routeId>#<kind> ids. From there, your agents and harnesses can hit the deployed endpoints using those assistant ids.

What Dawn does not do

Self-hosting

If you can't or won't use LangSmith, use the node target: Deploying to production (Node/Docker) above builds a server.mjs and Dockerfile that run the real Dawn runtime — Agent Protocol, AG-UI, /healthz, and the execution sandbox if configured. That's the self-hosting path.

The langsmith target's langgraph.json and per-route entry files can also be containerized independently with @langchain/langgraph-cli's langgraphjs dockerfile command, if you specifically want a LangGraph-Platform-compatible container rather than the Dawn runtime — but that image does not run Dawn's runtime and will not engage the sandbox, tool scoping, or permissions even if dawn.config.ts configures them.

Troubleshooting

  • Tests pass in-process but fail live-server — a tool or route isn't serializing cleanly. Check that inputs, outputs, and state are JSON-serializable (no Dates, Maps, classes).
  • Assistant id not found — the route in the request body doesn't match a <routeId>#<kind> key in .dawn/build/langgraph.json. Inspect that file directly (cat .dawn/build/langgraph.json) or run dawn verify --json to confirm what was discovered.
  • Type inference drifted — run dawn typegen locally and inspect .dawn/dawn.generated.d.ts. The generated file is ignored by the starter template, so regenerate it in CI/build steps unless your project chooses to commit .dawn/.

Related