Introduction
The twelve-factor app methodology is a set of best practices for building modern, cloud-native applications. Originally developed by Heroku, these principles apply to any platform.
The Twelve Factors
I. Codebase
One codebase tracked in version control, many deploys. Multiple apps sharing code should extract shared code into libraries.
II. Dependencies
Explicitly declare and isolate dependencies. Never rely on system-wide packages:
// package.json - explicit dependencies
{
"dependencies": {
"express": "^4.18.0",
"pg": "^8.11.0"
}
}III. Config
Store config in environment variables. Config varies between deploys; code doesn't:
const dbUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;IV. Backing Services
Treat backing services as attached resources. Databases, caches, and queues should be swappable without code changes:
# Production
DATABASE_URL=postgres://prod-db:5432/app
# Staging
DATABASE_URL=postgres://staging-db:5432/appV. Build, Release, Run
Strictly separate build and run stages:
- Build: Convert code into executable bundle
- Release: Combine build with config
- Run: Execute app in environment
VI. Processes
Execute the app as stateless processes. Any persistent data must be stored in a backing service:
// Bad - storing state in memory
let sessions = {};
// Good - use Redis for sessions
app.use(session({ store: new RedisStore() }));VII. Port Binding
Export services via port binding. The app is self-contained and doesn't rely on runtime injection of a webserver:
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on ${port}`));VIII. Concurrency
Scale out via the process model. Use multiple processes for different workload types:
web: node server.js
worker: node worker.js
scheduler: node scheduler.jsIX. Disposability
Maximize robustness with fast startup and graceful shutdown:
process.on('SIGTERM', async () => {
await server.close();
await db.disconnect();
process.exit(0);
});X. Dev/Prod Parity
Keep development, staging, and production as similar as possible. Use Docker to ensure consistency.
XI. Logs
Treat logs as event streams. Write to stdout; let the environment handle aggregation:
console.log(JSON.stringify({
level: 'info',
message: 'Order processed',
orderId: '123'
}));XII. Admin Processes
Run admin/management tasks as one-off processes in identical environments:
docker exec app node scripts/migrate.jsConclusion
Following the twelve-factor methodology creates applications that are portable, scalable, and maintainable across any cloud platform.