Twelve-Factor App — Cheat Sheet

Tags: architecture, cloud-native, devops, microservices, 12-factor, deployment

Level: intermediate

TL;DR: A methodology for building scalable, maintainable, cloud-native SaaS applications with declarative automation, continuous deployment, and maximum portability.

Key concepts

One codebase tracked in version control, mapped to many deploys (production, staging, dev).

Explicitly declare and isolate all dependencies using package managers and lockfiles.

Store configuration strictly in the environment, never hardcoded in the codebase.

Treat backing services (databases, caches, queues) as attached, interchangeable resources via URLs.

Strictly separate build, release, and run stages; releases must be immutable.

Execute the app as one or more stateless, share-independent processes; store state in backing services.

Export services by port binding instead of relying on runtime injection of web servers.

Scale out via the process model by assigning different process types to workloads.

Maximize robustness with fast startup and graceful shutdown handling (SIGTERM).

Keep development, staging, and production as similar as possible to minimize divergence.

Treat logs as unbuffered event streams routed to stdout, not local logfiles.

Run administrative and maintenance tasks as one-off processes in an identical environment.

Typical questions and ready answers

Q: How do you separate configuration from code effectively?R: I keep all environment-dependent values (database credentials, API keys, hostnames) in environment variables, loading them via runtime environment or .env files locally, ensuring zero secrets are committed to Git.

Q: What does stateless execution mean for horizontal scaling?R: The application processes store no persistent data or sticky sessions locally in memory or disk. Any shared state lives in backing services like Redis or PostgreSQL, allowing any instance to handle any request.

Q: Why must the build, release, and run stages be strictly isolated?R: The build transforms code and dependencies into a bundle, release combines that bundle with environment config to create a unique immutable release ID, and run executes it without runtime modifications.

Pitfalls and common mistakes

Hardcoding fallback credentials in source code when environment variables are missing.

Using sticky sessions on local web servers instead of external session stores.

Writing logs directly to local disk files instead of streaming to standard output.

Bundling database migration scripts inside runtime server startup loops.

Drifting dependencies by using different database engines between local development and production.

Snippets and commands

# Graceful shutdown handling in Node.js / TypeScript
process.on('SIGTERM', async () => {
  console.log('Received SIGTERM, closing server and db pool...');
  await server.close();
  await dbPool.end();
  process.exit(0);
});

Bash

# Twelve-Factor logging: write to stdout, delegate collection
echo "Starting app release $RELEASE_VERSION on port $PORT"

To review

[ ] Implement SIGTERM and SIGINT listeners across all long-running microservices.

[ ] Audit application settings to guarantee zero secrets exist in source control.

[x] Configure applications to output structured JSON logs directly to stdout.

References

The Twelve-Factor App specification (12factor.net)

Heroku Architecture Patterns & Cloud Native Computing Foundation (CNCF) best practices

Jarvis Interviews
Jarvis