Deployment
A Master app is two deployable services — the Next.js frontend and the MasterController API. Run them on one box or split them; both are plain Node processes. The backend already ships with what operators expect: health endpoints, graceful shutdown, JSON logs in production, compression and env-var configuration.
Build & run together#
$ npm ci$ master build # builds the Next.js frontend (the backend is plain ESM — no build)$ NODE_ENV=production master start # backend: node server.js, frontend: next start
master start sets NODE_ENV=production for the backend and passes the ports from master.config.js. In production the backend loads config/appsettings.production.json (JSON logs, warn level) and config/environments/env.production.json, and turns the Swagger UI off (the /openapi.json document stays available).
Environment variables#
Production configuration comes from environment variables — the same Section:Key names your code reads, written as Section__Key. Never deploy the development secrets file.
NODE_ENV=production
PORT=3001 # or Server__Port
FRONTEND_URL=https://example.com # CORS origin (or Frontend__Url)
Auth__JwtSecret=<32+ random characters> # enables JWT bearer auth (JWT_SECRET also works)
Auth__Issuer=my-app
Logging__LogLevel__Default=warnNODE_ENV=production
PORT=3000
NEXT_PUBLIC_API_URL=https://api.example.comDatabase credentials live in backend/config/environments/env.production.json, keyed by AppContext. Keep real passwords out of source — inject them at deploy time, or write that file from your secret store during the release. See Configuration and Secrets.
Migrations as a release step#
Apply pending migrations before the new version starts taking traffic — and review the SQL first if you like:
$ master db --env production script -o release.sql # optional: what will run$ master db --env production migrate # apply (each migration is atomic)$ master db --env production status # confirm
From inside backend/ without the CLI: NODE_ENV=production npx masterrecord update-database AppContext.
Health endpoints for load balancers#
server.js calls master.useHealthChecks() with a database check tagged ready, so every app exposes the ASP.NET-style trio:
| Endpoint | Use it for | Behaviour |
|---|---|---|
GET /health/live | Liveness probe | 200 Healthy while the process runs; 503 once shutdown begins. |
GET /health/ready | Readiness probe | Runs the ready-tagged checks (database canConnect()); 503 when a critical check fails or during graceful shutdown, so the balancer drains the instance. |
GET /health/report | Dashboards / humans | Every check with status, durationMs, data/error, plus uptimeSec. |
GET /health | The welcome page | A small { ok: true, ... } JSON ping from healthController. |
{
"status": "Healthy",
"totalDurationMs": 3,
"uptimeSec": 1842,
"checks": {
"database": { "status": "Healthy", "durationMs": 2 }
}
}Add more checks (Redis, an upstream API) with master.healthChecks.add(name, fn, { tags: ['ready'] }) — see Health Checks.
Graceful shutdown#
master.useGracefulShutdown() handles SIGTERM/SIGINT: readiness flips to 503, in-flight requests are drained, hosted services are stopped in order, and the process exits. Orchestrators that send SIGTERM and wait (Kubernetes, ECS, systemd, PM2) need no extra configuration — just make sure the stop timeout is longer than your slowest request.
Process manager (PM2)#
$ npm install -g pm2$$ cd backend && NODE_ENV=production PORT=3001 FRONTEND_URL=https://example.com Auth__JwtSecret=... pm2 start server.js --name app-api$ cd frontend && PORT=3000 NEXT_PUBLIC_API_URL=https://api.example.com pm2 start "npm run start" --name app-web$$ pm2 save && pm2 startup
Useful: pm2 list, pm2 logs app-api, pm2 restart app-web, pm2 monit.
Reverse proxy#
https://example.com/ -> Next.js (:3000)
https://api.example.com/ -> MasterController (:3001) health: /health/live, /health/readySet NEXT_PUBLIC_API_URL=https://api.example.com and FRONTEND_URL=https://example.com accordingly. Responses are already gzip/brotli compressed by the backend.
Backend hardening#
MasterController ships production security features (HTTPS/HSTS, CSRF, rate limiting, secure headers). See the MasterController deployment guide to enable HTTPS in server.js and run through the production checklist.
NEXT_PUBLIC_API_URL at the API, set FRONTEND_URLto the frontend origin for CORS, and point the host’s health check at /health/ready.