PushBackLog

The Twelve-Factor App

Advisory enforcement Complete by PushBackLog team
Topic: architecture Topic: quality Methodology: Cloud-native Skillset: backend Skillset: devops Technology: generic Stage: execution Stage: deployment

The Twelve-Factor App

Status: Complete
Category: Architecture
Default enforcement: Advisory
Author: PushBackLog team


Tags

  • Topic: architecture, quality
  • Methodology: Cloud-native
  • Skillset: backend, devops
  • Technology: generic
  • Stage: execution, deployment

Summary

The Twelve-Factor App is a methodology for building software-as-a-service applications that are portable, deployable to modern cloud platforms, and designed for continuous delivery. Its twelve factors address codebase management, dependencies, configuration, backing services, builds, processes, port binding, concurrency, disposability, parity, logging, and admin processes.


Rationale

Written for the cloud era

The Twelve-Factor methodology was documented by Adam Wiggins of Heroku in 2011, distilled from deployment patterns across thousands of applications. It describes what makes an application reliably deployable to cloud infrastructure, scalable horizontally, and maintainable over time. Fifteen years later it remains the baseline contract between an application and its platform.

Teams that follow the twelve factors produce applications that:

  • can be deployed to any cloud provider without code changes
  • scale horizontally by adding instances, not by enlarging servers
  • are operationally transparent — the platform can observe, restart, and route them without application-bespoke knowledge
  • can be developed in parity with production, reducing environment-specific defects

Each factor addresses a specific failure mode

The factors aren’t arbitrary rules. Each one addresses a specific class of operational or architectural problem observed in pre-cloud, “traditional” application deployment:

  • Locked to a specific OS or server → Factor I (Codebase), III (Config)
  • Works on developer laptop, fails in production → Factor X (Dev/prod parity)
  • Cannot scale without sticky sessions → Factor VI (Stateless processes)
  • Debugging requires SSH into production → Factor XI (Logs)

Guidance

The twelve factors

#FactorWhat it means
ICodebaseOne codebase tracked in version control; many deploys (dev, staging, prod) from the same codebase. Not one repo per environment.
IIDependenciesExplicitly declare all dependencies (package.json, requirements.txt, go.mod). Never assume system-level tools exist. Use dependency isolation (virtualenv, node_modules).
IIIConfigEverything that varies between deploys (database URLs, API keys, feature flags) is stored in environment variables, not in code or committed files.
IVBacking servicesDatabases, queues, caches, email services are attached resources — accessed by URL in config. Swap a local Postgres for an RDS instance by changing an env var; no code changes.
VBuild, release, runStrictly separate: build (compile, bundle) → release (build + config) → run (execute). Never modify code in a running instance. Releases are immutable; roll back by deploying a previous release.
VIProcessesExecute the app as stateless processes. No sticky sessions, no local file state between requests. State lives in backing services (database, cache, queue).
VIIPort bindingThe app exports its service by binding to a port. It doesn’t require a web server embedded in the runtime; the app IS the web server. Enables app-to-app communication as backing services.
VIIIConcurrencyScale out by adding more processes, not by making the process larger. Use the OS process model; use worker types (web, worker, clock) to scale each concern independently.
IXDisposabilityProcesses can start fast and stop gracefully. Fast startup enables elastic scaling. Graceful shutdown (handle SIGTERM, finish in-flight requests) prevents data loss.
XDev/prod parityKeep development, staging, and production as similar as possible: same backing service versions, same OS, deployed continuously rather than in big batches.
XILogsTreat logs as event streams. The app writes to stdout; the platform collects, routes, and stores logs. No log file management in the app.
XIIAdmin processesRun management tasks (migrations, one-time scripts) as one-off processes in the same environment as the app. Not cron jobs, not SSH sessions — disposable run commands.

The most commonly violated factors

In practice, teams most frequently violate:

  • III (Config): credentials in code or committed .env files
  • X (Dev/prod parity): using SQLite locally, PostgreSQL in production
  • VI (Processes): storing uploaded files on the local filesystem (lost on restart)
  • XI (Logs): writing rotating log files instead of stdout

Examples

Factor III: Config in env vars

# Wrong: config in committed file
# config/database.js
module.exports = { host: 'prod-db.internal', user: 'admin', password: 'secret' };

# Right: read from environment at runtime
const config = {
  databaseUrl: process.env.DATABASE_URL,   // injected by platform
  stripeKey: process.env.STRIPE_SECRET_KEY
};

Factor VI: Stateless processes

// Wrong: in-memory session state
const sessions = new Map<string, Session>(); // Lost on restart; breaks with multiple instances

// Right: sessions in a backing service
const session = await redis.get(`session:${sessionId}`);

Factor IX: Graceful shutdown

process.on('SIGTERM', async () => {
  await server.close();  // Stop accepting new requests
  await db.end();        // Close DB pool cleanly
  process.exit(0);
});

Anti-patterns

1. Sticky sessions

Routing users to specific instances breaks horizontal scale. Factor VI requires that any instance can handle any request. Use a shared session store (Redis, database) instead.

2. Different databases in dev and production

SQLite locally, PostgreSQL in production. Bugs that only appear in production are the direct consequence. Factor X requires the same backing service type and version across environments.

3. Bundling config into images

Baking database URLs or API keys into container images produces images that are environment-specific. The image should be environment-agnostic; config is injected at runtime.

4. Cron jobs that SSH into servers

Factor XII says admin processes should run as disposable processes in the same environment as the app. Arbitrary crons that shell into production are untracked, unversioned, and invisible.



Part of the PushBackLog Best Practices Library. Suggest improvements →