ReviseAlgo Logo

Microservices Architecture

The 12-Factor App — Principles Every Microservice Must Follow

Applying statelessness, config environments separation, processes concurrency, and logging standards.

Last Updated: June 14, 2026 15 min read

Introduction

The Twelve-Factor App is a methodology consisting of 12 design principles for building modern, cloud-native SaaS applications. Originally formulated by Heroku engineers, these factors serve as a blueprint for designing portable, stateless, resilient, and highly scalable Spring Boot microservices.

Why It Matters

Cloud deployments (Kubernetes, AWS ECS) manage applications as ephemeral container instances that start, stop, and scale automatically. Apps that violate 12-factor rules (e.g. hardcoding database connection keys, saving uploaded files to local directories, or keeping sessions in local memory) are fragile, difficult to configure, and fail to scale horizontally.

Real-World Analogy

Think of a 12-factor microservice like a standard shipping container. It has standardized size boundaries, fits on any cargo ship or train car, has clear hooks for connecting power, and handles cargo independently. It works anywhere in the world because it adheres to strict structural standards.

Detailed Mechanics

Deep-Dive: Key Twelve-Factor Principles

  • 1. Codebase: One codebase tracked in git, deployed in many environments (Dev, Staging, Prod).
  • 2. Dependencies: Explicitly declare and isolate dependencies (e.g. using Maven pom.xml or Gradle files; never bundle internal libraries on host runtimes).
  • 3. Config: Store config in the environment. Never hardcode credentials in code. Use environment variables or Spring Cloud Config.
  • 4. Backing Services: Treat backing services (databases, caches, brokers) as attached resources. Swap from local H2 to RDS Postgres without modifying code.
  • 5. Build, Release, Run: Strictly separate stages. Build compiles the code, Release combines the JAR with config, and Run boots the container.
  • 6. Processes: Execute the app as one or more stateless processes. Never store persistent state on local filesystems; use Amazon S3 or databases.
  • 7. Port Binding: Export services via port binding (e.g., embedded Tomcat exposes web services by binding directly to port 8080).
  • 8. Concurrency: Scale out via the process model. Scale horizontally by running multiple pods/instances, rather than making single JVMs larger.
  • 9. Disposability: Maximize robustness with fast startup and graceful shutdown. Apps must process SIGTERM signals correctly to close active connections cleanly.
  • 10. Dev/Prod Parity: Keep development, staging, and production as similar as possible to reduce "works on my machine" issues.
  • 11. Logs: Treat logs as event streams. Write logs exclusively to standard output (console/stdout) and let infrastructure tools (fluentd/Elasticsearch) capture and aggregate them.
  • 12. Admin Processes: Run administrative tasks (like migrations) as one-off processes in the same environment.

Practical Example

The configuration below implements **Factor 3 (Config)** by injecting values from system environment variables with fallback defaults inside application.properties:

Quick Quiz

Q1: According to Twelve-Factor principles, why is it bad practice to write log events directly to a local log file inside a microservice container?

A) Logging to files consumes too much network bandwidth.

B) Container filesystems are ephemeral (non-persistent). If the container crashes or gets rescheduled, logs are lost forever. Apps should write to stdout/stderr and let external aggregators capture them.

C) Java does not support writing files in Linux.

D) Writing files requires root access privileges.

Answer: B — Decoupling log capture from log creation makes containers stateless and simplifies log aggregation.

Q2: What is the main purpose of separating Build, Release, and Run stages?

A) To allow programmers to work on different timezones.

B) It is required to make Java code compile faster.

C) To guarantee that code compiled once (Build) can be configured dynamically for different environments (Release) and executed state-independently (Run) without recompiling.

D) It automatically sets database constraints.

Answer: C — Separating stages ensures target deployment stability: release configurations can be modified without altering compilation binaries.

Scenario-Based Challenge

Production Scenario:

You deploy your Spring Boot microservice to a Kubernetes cluster. Every time the cluster scales out (adds pod instances) under traffic load, users report that their active shopping carts disappear. What Twelve-Factor rule was violated, and how do you resolve it?

View Solution

This violates **Factor 6 (Processes)**: the app must run as one or more stateless processes. Shopping cart data was being stored inside the local HTTP session (in-memory JVM heap memory). When Kubernetes load balanced requests to new pod instances, they lacked access to that memory. To resolve this:

  1. Remove in-memory session dependencies: make application endpoints stateless.
  2. Store user shopping carts in a centralized **attached backing service** (Factor 4) such as Redis or a database.
  3. Configure Spring Session (e.g. spring-session-data-redis) to transparently route session queries to the Redis cache.

Interview Questions

1. Conceptual: How does Spring Boot enforce Factor 7 (Port binding)?

Traditionally, Java apps were packaged as WAR files and deployed onto external servers (Tomcat/JBoss). Spring Boot embeds web containers directly inside the executable JAR. At runtime, the process self-hosts and exports its services by binding directly to port server.port, requiring no external server installs.

2. Concept: How can you implement Factor 9 (Disposability) in Spring Boot?

Enable graceful shutdowns in your configuration: server.shutdown=graceful. When Kubernetes shuts down a pod instance, it sends a SIGTERM signal. Spring Boot intercept triggers, rejects new incoming requests, and gives active requests a designated buffer time (e.g., 30s) to complete processing before terminating.

Production Considerations

Never build container images that embed environment-specific configurations. Maintain Dev/Prod parity by testing application behaviors locally using container orchestration toolsets (like Docker Compose) mimicking staging/production topologies.