twelve-factor app
The twelve-factor app is a methodology for building software-as-a-service applications as twelve declarative practices. The factors make a service portable across runtimes, scalable through process replication, and easy to deploy to a modern cloud platform.
The methodology was published by Adam Wiggins at Heroku in 2011 and last revised in 2017. Its language-agnostic vocabulary now shows up in almost every cloud-native deployment discussion a Python developer joins.
The twelve factors are:
- Codebase: one codebase tracked in version control, many deploys.
- Dependencies: explicitly declare and isolate dependencies.
- Config: store config in environment variables.
- Backing services: treat backing services as attached resources.
- Build, release, run: strictly separate the build and run stages.
- Processes: execute the app as one or more stateless processes.
- Port binding: export services by binding to a port.
- Concurrency: scale out via the process model.
- Disposability: maximize robustness with fast startup and graceful shutdown.
- Dev/prod parity: keep development, staging, and production as similar as possible.
- Logs: treat logs as event streams.
- Admin processes: run admin and management tasks as one-off processes.
How It Shows Up in Practice
The twelve factors are the implicit rules behind a Heroku, Render, Fly, Railway, AWS App Runner, Google Cloud Run, or Kubernetes deployment. Each platform’s happy path assumes a single repository and a declared dependency manifest such as requirements.txt or pyproject.toml.
Configuration arrives as environment variables. Stateless web processes can be replaced freely. Logs go to stdout. A database connection is expressed as a URL pointed at by an env var.
Config and logs, Factors 3 and 11, are the most visible in a Python codebase. A twelve-factor service reads its configuration from os.environ instead of a checked-in settings module, and emits unbuffered log lines on stdout so the platform can aggregate, rotate, and route them:
import logging
import os
import sys
DATABASE_URL = os.environ.get("DATABASE_URL", "postgres://localhost/app")
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
DEBUG = os.environ.get("DEBUG", "0") == "1"
logging.basicConfig(
stream=sys.stdout,
level=LOG_LEVEL,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
log = logging.getLogger("checkout")
log.info(
"starting service db=%s debug=%s",
DATABASE_URL.rsplit("/", 1)[-1],
DEBUG,
)
2026-05-27 12:00:00,000 INFO checkout starting service db=app debug=False
Adam Wiggins phrased the config rule as a litmus test: an app has its configuration correctly factored out if the entire codebase could be open-sourced without leaking a single credential.
Common Pitfalls
The twelve factors are easy to violate in ways that only hurt at scale. The most common pitfall in Python services is keeping state in process memory, such as caching session tokens in a module-level dict, then deploying multiple replicas behind a load balancer.
The cache is not shared, so users see logged-out sessions whenever the load balancer routes them to a different replica. Factor 6 explicitly rejects this design and routes session state to a stateful backing service such as Redis or a database.
Other recurring slips include committing secrets to settings.py, writing log files to disk, or running database migrations from inside the web process instead of as a one-off admin command. Pinning to a system-wide Python install rather than an isolated environment violates Factor 2.
The methodology predates containerization but maps cleanly onto it. A Dockerfile builds the immutable artifact for Factor 5. Environment variables fed at docker run time satisfy Factor 3. A docker stop that sends SIGTERM exercises Factor 9.
Some factors fit twelve-factor’s original PaaS context better than they fit modern serverless or stateful workloads, particularly the stdout-only log handling and strict statelessness. Even so, the vocabulary remains the shared baseline almost every cloud platform expects an application to meet.
Related Resources
Tutorial
Deploying a Python Flask Example Application Using Heroku
In this step-by-step tutorial, you'll learn how to create a Python Flask example web application and deploy it using Heroku.
For additional information on related topics, take a look at the following resources:
- Hosting a Django Project on Heroku (Tutorial)
- Securely Deploy a Django App With Gunicorn, Nginx, & HTTPS (Tutorial)
- Run Python Versions in Docker: How to Try the Latest Python Release (Tutorial)
- Python Web Applications: Deploy Your Script as a Flask App (Tutorial)
- Logging in Python (Tutorial)
- Continuous Integration and Deployment for Python With GitHub Actions (Tutorial)
- Deploying a Flask Application Using Heroku (Course)
- Host Your Django Project on Heroku (Course)
- Deploy a Django App With Gunicorn and Nginx (Course)
- Deploy Your Python Script on the Web With Flask (Course)
- Logging Inside Python (Course)
- Logging in Python (Quiz)
- Python Continuous Integration and Deployment Using GitHub Actions (Course)
- GitHub Actions for Python (Quiz)
By Martin Breuss • Updated June 1, 2026