Q&A
What is the twelve-factor app methodology?
Overview
Published by Heroku engineers (Adam Wiggins, 2011), the Twelve Factors are a distillation of best practices observed across thousands of deployed apps. They're deliberately language- and platform-agnostic - the principles apply whether you're building in Python, Java, Node, or Go, deploying on Heroku, AWS, or Kubernetes. Together they guide you away from the most common portability and operational pitfalls.
graph TD
A[Twelve-Factor App] --> B["Codebase, Dependencies, Config"]
A --> C["Backing Services, Build/Release/Run"]
A --> D["Processes, Port Binding, Concurrency"]
A --> E["Disposability, Dev/Prod Parity, Logs, Admin"]
style A fill:#1e1b4b,color:#fff
The 12 Factors
I. Codebase
One codebase tracked in version control; many deploys. A single repo deploys to multiple environments (dev, staging, prod). If multiple apps share code, extract shared libraries - they shouldn't share a single repo.
II. Dependencies
Explicitly declare and isolate dependencies. Never rely on system-wide packages. Use a manifest (requirements.txt, package.json, pom.xml) and a dependency isolation mechanism (virtualenv, npm, Docker) so the app doesn't silently use something from the host OS.
III. Config
Store config in the environment. Anything that varies between deploys (database URLs, API keys, ports) must be in environment variables - never hard-coded or in committed config files. A codebase should be able to be made open source without exposing credentials.
IV. Backing Services
Treat backing services as attached resources. Databases, queues, caches, email services are all "attached resources" accessed via URL/config. You should be able to swap one (e.g. local Postgres for an RDS instance) by changing a URL in the config, without any code change.
V. Build, Release, Run
Strictly separate build and run stages. Build: compile/assemble the artifact. Release: combine the artifact with the config for a specific environment (an immutable, tagged release). Run: execute the release. Never modify code at runtime; to change code, create a new release.
VI. Processes
Execute the app as one or more stateless processes. Processes share nothing - no sticky sessions, no in-memory session state. Any data that needs to persist must go in a backing service (database, cache). This makes each process replaceable and independently scalable.
VII. Port Binding
Export services via port binding. The app is self-contained and exposes its service on a port (not relying on a web server injection like mod_php). A web server library (Express, Gunicorn, Puma) is declared as a dependency and binds a port directly. This makes the app its own server.
VIII. Concurrency
Scale out via the process model. Scale by adding more processes (horizontal), not by making one process bigger. Different workload types run as separate process types (web workers, background jobs), each independently scalable.
IX. Disposability
Maximize robustness with fast startup and graceful shutdown. Processes should start quickly (seconds) and shut down gracefully on SIGTERM (finish in-flight requests, release resources). This supports elastic scaling, rapid deployment, and resilience.
X. Dev/Prod Parity
Keep development, staging, and production as similar as possible. Minimize the time, people, and tools gap between environments. Use the same backing services locally as in production (containerize or use dev databases of the same type). This catches environment-specific bugs early.
XI. Logs
Treat logs as event streams. Apps should never manage log files themselves. Instead, write all log output to stdout - unbuffered. The execution environment (Docker, Kubernetes, a log aggregator) handles routing, storage, and analysis. The app doesn't know or care where its logs end up.
XII. Admin Processes
Run admin/management tasks as one-off processes. Database migrations, REPL sessions, one-time scripts should run in an identical environment (same release, same config) as regular processes. Ship admin code with the app, not in ad hoc scripts outside version control.
Why It Matters
Following the 12 factors produces apps that are:
- Portable - run anywhere (local, cloud, container).
- Scalable - stateless processes scale horizontally.
- Maintainable - explicit dependencies, config in env, parity across environments.
- Operable - fast/graceful start/stop, log streams, declarative releases.
Why This Matters in Interviews
System-design and DevOps interviews use the 12-factor methodology to assess cloud-native maturity. The most frequently tested factors are III (config in env, not code), VI (stateless processes), X (dev/prod parity), XI (logs as event streams to stdout), and IX (disposability). Being able to explain each in a sentence and give a concrete violation ("storing session in memory violates Factor VI") is more valuable than just listing the names.
Common Pitfalls
- Hard-coded credentials (violates Factor III - config should be in env vars).
- In-memory session state (violates Factor VI - processes must be stateless).
- Different databases in dev vs prod (violates Factor X - e.g. SQLite in dev, Postgres in prod).
- Writing log files directly (violates Factor XI - write to stdout instead).
- Deployment-time code modification (violates Factor V - immutable builds/releases).
References
- The Twelve-Factor App: https://12factor.net/