Home/Learn/Microservices/12-Factor App Principles

12-Factor App Principles

Intermediate
Fundamentals

The 12-Factor methodology (codebase, dependencies, config, backing services, build/release/run, processes, port binding, concurrency, disposability, dev/prod parity, logs, admin) defines best practices for cloud-native services.

Overview

The 12-Factor App methodology, documented by Heroku engineers around 2012, describes 12 principles for building modern, cloud-native software-as-a-service applications. These principles emerged from hard-won experience running many applications in production and address portability, scalability, reliability, and developer ergonomics. While the manifesto predates Kubernetes, virtually every principle maps directly to how modern Spring Boot microservices are built and deployed in containers. Each factor is a specific, actionable guideline — not a vague philosophy. Understanding all 12 and being able to explain how Spring Boot implements them is a strong interview signal for senior engineer roles.

Factors I–VI — Codebase to Processes

**I. Codebase** — One codebase tracked in version control, deployed to many environments. One Git repo per service; different deployments (dev, staging, prod) from the same repo via environment variables, not branches.

**II. Dependencies** — Explicitly declare all dependencies; never rely on system-wide packages. In Java: declare everything in pom.xml or build.gradle, including the JDK version (Docker image tag).

**III. Config** — Store config that varies between deploys in environment variables, not in code or property files committed to VCS. In Spring Boot: use `${ENV_VAR}` in application.yml and inject via `@Value` or `@ConfigurationProperties`.

**IV. Backing Services** — Treat databases, caches, message queues, and external APIs as attached resources configured by URL/credentials from config — not hardcoded. Swap a prod DB for a local one by changing an env var.

**V. Build, Release, Run** — Strictly separate build (compile → JAR), release (JAR + env-specific config), and run (execute). A release is immutable — never change running code without a new release.

**VI. Processes** — Execute the app as one or more stateless processes. No sticky sessions; session state in Redis, not in-process memory.

YAML / Dockerfile — Factors III–V
# Factor III — Config from environment variables in Spring Boot
# application.yml
spring:
  datasource:
    url: ${DB_URL}           # from env var — never hardcode
    username: ${DB_USER}
    password: ${DB_PASS}
  kafka:
    bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS}

# Factor IV — Backing services as attached resources
# Swap local DB for prod by changing one env var:
# local:  DB_URL=jdbc:h2:mem:devdb
# prod:   DB_URL=jdbc:mysql://prod-db.example.com:3306/orders

# Factor V — Build → Release → Run with Docker
# Build: produces immutable JAR
FROM eclipse-temurin:21-jre AS base
COPY target/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
# Runtime config (Factor III) injected via K8s ConfigMap / Secret

Factors VII–XII — Ports to Admin

**VII. Port Binding** — Export services via port binding; the app is self-contained (embedded Tomcat) and exposes its own port. No WAR deployment to an external container.

**VIII. Concurrency** — Scale out horizontally by adding processes, not by making one process larger. Kafka consumers scale by adding pods up to the partition count.

**IX. Disposability** — Processes start fast and shut down gracefully. Spring Boot supports graceful shutdown (spring.lifecycle.timeout-per-shutdown-phase) and handles SIGTERM.

**X. Dev/Prod Parity** — Keep dev, staging, and prod as similar as possible. Use Docker Compose locally; use the same DB version in dev as in prod (no H2-in-prod-MySQL-in-dev mismatch).

**XI. Logs** — Treat logs as event streams. The app writes to stdout/stderr only; log aggregation (Loki, Elasticsearch) is the platform's responsibility.

**XII. Admin Processes** — Run admin/management tasks (DB migrations, REPL) as one-off processes. Use Flyway migrations that run at startup, or a separate admin container.

YAML + XML — Factors IX, XI, XII
# Factor IX — Graceful shutdown in Spring Boot
# application.yml
server:
  shutdown: graceful          # wait for in-flight requests to complete
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s  # wait up to 30s for requests to finish

# Factor XI — Logs to stdout only (12-Factor compliant)
# logback-spring.xml
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>{"timestamp":"%d{ISO8601}","level":"%level","service":"order-service",
              "traceId":"%X{traceId}","message":"%msg"}%n</pattern>
  </encoder>
</appender>
# Platform (Kubernetes DaemonSet, Fluentd) ships logs to Loki/Elasticsearch

# Factor XII — DB migrations as admin process (Flyway)
<dependency>
  <groupId>org.flywaydb</groupId>
  <artifactId>flyway-core</artifactId>
</dependency>
# Runs on startup: src/main/resources/db/migration/V1__create_orders.sql

Spring Boot and the 12 Factors — Quick Map

Spring Boot implements or facilitates every factor out of the box with minimal configuration.

Java — 12-Factor Spring Boot Map
// 12-Factor Spring Boot Compliance Checklist:
//
// I.   Codebase        → one Git repo per service; multiple envs via env vars
// II.  Dependencies    → pom.xml / build.gradle; spring-boot-starter BOM
// III. Config          → application.yml with ${ENV_VAR} substitution; @ConfigurationProperties
// IV.  Backing Services→ DataSource, KafkaTemplate, RedisTemplate all URL-configured
// V.   Build/Release   → Maven/Gradle build → Docker image → K8s deployment (immutable)
// VI.  Processes       → stateless @Service beans; sessions in Redis (spring-session)
// VII. Port Binding    → embedded Tomcat; server.port=8080
// VIII.Concurrency     → scale via replica count in K8s Deployment / Kafka partitions
// IX.  Disposability   → server.shutdown=graceful; @PreDestroy for cleanup
// X.   Dev/Prod Parity → Docker Compose locally; same DB in dev & prod
// XI.  Logs            → spring-boot-starter-logging → stdout; JSON via Logback
// XII. Admin Processes → Flyway migrations; Spring Boot Admin; Actuator /health

Key Points to Remember

  • 1Factor III (Config) is the most practically important: never hardcode environment-specific config — use env vars injected at runtime.
  • 2Factor VI (Processes): stateless services scale horizontally — no sticky sessions, no in-memory state shared between requests.
  • 3Factor IX (Disposability): set `server.shutdown=graceful` in Spring Boot to handle SIGTERM from Kubernetes gracefully.
  • 4Factor XI (Logs): write to stdout only — the platform aggregates logs; never write to log files inside the container.
  • 5Factor X (Dev/Prod Parity): use the same database engine locally as in production; H2 in dev with MySQL in prod hides SQL compatibility bugs.
  • 6The 12 factors predate Kubernetes but map directly to K8s primitives: ConfigMaps (III), ReplicaSets (VIII), SIGTERM handling (IX), and DaemonSet log shipping (XI).

Interview Questions

Sign in to ask Aria
1

What is the 12-Factor App methodology and why was it created?

EasyAmazon
2

How does Factor III (Config) apply to a Spring Boot microservice deployed in Kubernetes?

MediumUber
3

Why should a 12-Factor app be stateless (Factor VI)? How do you handle user sessions?

MediumGoogle
4

What is the recommended log strategy for a 12-Factor app and how do you implement it in Spring Boot?

MediumNetflix
5

A developer argues that using H2 in dev and MySQL in prod is fine because they both support SQL. Which 12-factor principle does this violate and why is it risky?

HardLinkedIn

Ask Aria about 12-Factor App Principles

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…