Production Checklist
Use this checklist to ensure your Unchained Engine deployment is production-ready. For the full list of configuration options, see Environment Variables — this page only covers what typically goes wrong at launch.
Environment
-
NODE_ENV=production- Enables production behavior across the engine (and turns off email interception, see below) - Required boot variables set -
startPlatformexits ifROOT_URL,UNCHAINED_TOKEN_SECRET,EMAIL_WEBSITE_NAME,EMAIL_WEBSITE_URL, orEMAIL_FROMare missing -
UNCHAINED_TOKEN_SECRET- Strong, unique, minimum 32 characters (boot fails otherwise) -
MONGO_URLset - Without it, the engine spawns a localmongod(viamongodb-memory-server) that stores its data in./.db. Data does survive restarts, but this is not production-appropriate: an unmanaged, single-node local mongod with no backups, replication, or authentication - No secrets in code or images - All secrets from environment
- Seed/admin credentials rotated - Don't ship
UNCHAINED_SEED_PASSWORD-style development passwords
# Generate a secure secret
openssl rand -base64 32 # For UNCHAINED_TOKEN_SECRET
Cookies & Sessions
- HTTPS enforced - Cookies default to
secure; never setUNCHAINED_COOKIE_INSECUREin production -
UNCHAINED_COOKIE_SAMESITEreviewed - Default islax; only setnoneif your storefront runs on a different site, and only over HTTPS -
UNCHAINED_COOKIE_DOMAINset - If storefront and engine share a parent domain
See Security for the full cookie reference.
CORS
The engine does not restrict origins itself: the GraphQL endpoint (GraphQL Yoga) reflects the request Origin header by default, and allowRemoteToLocalhostSecureCookies is a development-only mode that throws in production. To restrict cross-origin access:
- Enforce allowed origins at your reverse proxy/CDN - This covers all routes (GraphQL, webhooks,
/chat) - Optionally pass Yoga's
corsoption throughstartPlatformfor the GraphQL endpoint:
await startPlatform({
cors: {
origin: ['https://myshop.com'],
credentials: true,
},
});
The /mcp endpoint has its own built-in Origin/Host validation based on ROOT_URL.
Audit Logging
- Audit events shipped -
UNCHAINED_LOG_FORMAT=jsonset and a log agent scrapes theunchained:auditlines, or OTLP push configured - Collector reachable (if pushing) -
collectorUrl/OTEL_EXPORTER_OTLP_ENDPOINTpoints at your OTLP collector - Retention in the log pipeline - your SIEM/log store retains audit events per your compliance requirements
const platform = await startPlatform({
auditLog: {
collectorUrl: process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, // or rely on the env fallback
},
});
Database
- MongoDB authentication - Database requires authentication, not publicly accessible
- Encrypted connections - MongoDB connection uses TLS
- Regular backups - Automated backup schedule configured
Unchained creates its indexes automatically at startup; custom indexes are only needed for custom fields you query on.
File Storage
- Storage plugin registered - GridFS (default in presets) or MinIO/S3
- GridFS:
UNCHAINED_GRIDFS_PUT_UPLOAD_SECRETset (required for PUT uploads and signed downloads) - MinIO/S3:
MINIO_ENDPOINT(full URL),MINIO_ACCESS_KEY,MINIO_SECRET_KEY,MINIO_BUCKET_NAMEset
See File Uploads.
Email
-
MAIL_URLconfigured - SMTP connection string; no emails are sent without it - Interception off - Outside production, emails are intercepted (logged, not sent) unless
UNCHAINED_DISABLE_EMAIL_INTERCEPTIONis set. WithNODE_ENV=production, emails are always sent — make sure that's what you deploy with - Order confirmation and password reset tested - Against the real SMTP server
Payment Providers
- Production API keys - Not using test/sandbox keys
- Webhooks pointed at production - e.g. Stripe's webhook to
https://api.myshop.com/payment/stripe/webhook - Webhook secrets set - Signatures are validated
# Stripe plugin
STRIPE_SECRET=sk_live_...
STRIPE_ENDPOINT_SECRET=whsec_...
Initial Data
- Countries, currencies, languages - Active entities configured (Admin UI or seed)
- Products published - Correct status and prices in all active currencies
- At least one active payment and delivery provider - Checkout fails without both
Operations
- Rate limiting at reverse proxy - See Security
- Health probes - Liveness/readiness routes wired up, see Docker Deployment
- Structured logs collected -
UNCHAINED_LOG_FORMAT=jsonfor log pipelines,LOG_LEVEL=Info - Full checkout tested on staging - Cart → delivery → payment → confirmation email
Quick Verification Commands
# Check Node.js version (needs 26+)
node --version
# Test MongoDB connection
mongosh "$MONGO_URL" --eval "db.adminCommand('ping')"
# Test API endpoint
curl https://api.myshop.com/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ shopInfo { _id } }"}'
Related Documentation
- Security Guide - Security features and practices
- Environment Variables - Full configuration reference
- Docker Deployment - Container deployment
- Audit Logging - OCSF audit logging