Production Readiness
Use this checklist to take a Glasswork service from "it runs locally" to "safe in production". Skim top-to-bottom on first deploy; revisit when adding new modules.
Quick Checklist
- ✅ Disable public docs:
openapi.serveSpecs = false,openapi.serveUI = false - ✅ Turn on rate limiting:
rateLimit.enabled = true, DynamoDB store in prod - ✅ Lock down CORS: explicit origins + credentials only if required
- ✅ Secure headers: enable
middleware.secureHeaders - ✅ Authentication: implement middleware; never rely on
publicflag alone - ✅ Secrets from env: load from SSM/Secrets Manager; never commit secrets
- ✅ Structured logging: Pino JSON with requestId + service names
- ✅ Exception tracking: CloudWatch tracker or Sentry/AppSignal
- ✅ TLS everywhere: HTTPS and HSTS at CDN/ALB/API Gateway
- ✅ Database hygiene: pool sizing, connection reuse, migrations applied
- ✅ Email: out of SES sandbox; verified sender identities
Not on Lambda?
This checklist assumes Lambda. For containers/Kubernetes:
- Keep health/readiness endpoints enabled
- Size connection pools for pod concurrency (not Lambda)
- Replace Function URL/CORS guidance with your ingress settings
- Skip provisioned concurrency/SnapStart notes
Essentials (Before Traffic)
1. Secure Surface
OpenAPI exposure:
typescript
const { app } = await bootstrap(AppModule, {
openapi: {
enabled: true,
serveSpecs: false, // Don't expose in production
serveUI: false,
},
});Keep writeToFile if you need to publish specs to an artifact store or gateway.
Rate limiting & CORS:
typescript
const { app } = await bootstrap(AppModule, {
rateLimit: {
enabled: true,
storage: 'dynamodb',
windowMs: 60_000,
maxRequests: 100,
},
middleware: {
cors: {
origin: ['https://app.example.com'],
credentials: true,
},
secureHeaders: true,
},
});2. Authentication & Authorization
- Implement auth middleware;
public: trueonly marks docs as unauthenticated. - Document auth scheme in OpenAPI and verify 401/403 responses are present.
- Prefer short-lived access tokens and server-side sessions.
- Strip sensitive headers from logs.
3. Configuration & Secrets
- Set
NODE_ENV=production; run with"type": "module"and strict TS build. - Load secrets from env/SSM/Secrets Manager; never hardcode.
- Validate configuration via
createConfigat startup. - Default to least privilege IAM roles; restrict SES identities and S3 buckets.
4. Health & Readiness (Container Deployments)
Lambda Note
Health endpoints are primarily for container/server deployments (ECS, Kubernetes, ALB). Lambda doesn't need them. AWS manages instance health automatically.
For container deployments:
- Add a cheap, dependency-light endpoint (e.g.
/internal/health). - Exclude it from OpenAPI with
openapi: { exclude: true }on the route. - Optionally add a deeper readiness check that touches DB/queues.
5. Observability
Logging:
- Use
pinowith the providedlambdaPinoConfig. - Prefer
createContextAwarePinoLoggerin services for consistent fields. - Ship requestId + service name in every log line.
- Avoid logging secrets (tokens, passwords, PII).
Error handling:
- Rely on domain exceptions (
NotFoundException,BadRequestException, etc.). - Keep a default error handler; do not leak stack traces in production responses.
- Track 5xx errors at minimum. Consider including 404s for critical resources.
Metrics:
- Track latency, 4xx/5xx rates, rate-limit hits, cold starts.
- Enable CloudWatch alarms for error rate, latency, and cold start spikes.
6. Data Safety
- Validate all input via Valibot schemas.
- Enforce response validation for external-facing routes (prevents data leaks).
- Use
strictTypes: truefor sensitive responses. - Back up production databases; enable RDS performance insights and error logs.
7. Database & Connection Management
- Size connection pools for Lambda concurrency or server threads.
- Reuse clients across invocations; avoid creating clients per request.
- For Lambda + Postgres, use PgBouncer/RDS Proxy; set low pool size.
- Run migrations before deploy; block boot if pending migrations remain.
8. Email Hygiene
- Move SES out of sandbox before production; verify sender identities.
- Set
configurationSetto emit bounces/complaints; alarm on high rates. - For dev/staging, keep sandbox on and point to non-customer mailboxes.
Deploy Safely
- Immutable builds: use esbuild with
format: 'esm',keepNames: true,external: ['@aws-sdk/*']. - Infrastructure: prefer SAM/CDK/Terraform; pin runtime to
nodejs20.x+; set memory + timeout per workload. - Cold starts: minimize bundle size; use provisioned concurrency for critical paths; reuse DI container.
- Static assets: serve from CDN/S3; do not serve from app.
Safety Nets Before Launch
- End-to-end smoke test (auth + one read + one write) in staging.
- Run lint, format, and tests on CI.
- Toggle feature flags via config, not code.
- Document rollback procedure (last known good build + infra change).
- Set timeouts: HTTP clients, DB queries, and Lambda function timeout.
- Use idempotency where appropriate for background jobs and webhooks.
Optional But Valuable
- Security: Content Security Policy headers; JWT/session rotation; audit logging.
- Operational: request sampling for logs; structured logging only (no
console.logdumps). - Data: soft deletes for key tables; migrations with down scripts.
Adding Module Features
When adding new modules (background jobs, caching, auth, CLI, multi-tenancy), document:
- How it changes deployment (queues, cache, roles).
- Observability knobs (metrics/logs).
- Failure modes and rollbacks.
Learn More
- Observability Guide - Logging and metrics setup
- OpenAPI Guide - Lock in your API surface
- Testing Guide - Add robust tests
- Lambda Deployment - Optimize for serverless
