Cloud Native Microservices: How and Why
The Twelve-Factor App
This methodology is a set of principles for building applications that are designed to be deployed and operated as software-as-a-service (SaaS). It was developed by the team at Heroku, one of the earliest providers of platform-as-a-service (PaaS) solutions, and has since been widely adopted by the software engineering community. As you can understand from its name, the Twelve-Factor App methodology highlights twelve factors. Some of them may be obvious today, but they were far from being commonly adopted years ago.
Codebase
The Twelve-Factor App methodology states that an app should have one codebase, tracked in a version control system like Git or Mercurial. The codebase should be a single repository or a set of repositories sharing a common root commit.
Multiple codebases indicate a distributed system, where each component should be treated as a separate app. Shared code across apps violates this principle—such code should be extracted into libraries and included through a dependency manager.
An app can have many deploys (production, staging, local), but the codebase stays the same across all of them: one codebase tracked in revision control, many deploys.
Developers should always work from the same codebase in their local environment.
Dependencies
The second factor emphasizes explicitly declaring and isolating dependencies.
A Twelve-Factor App must declare all dependencies in a dependency manifest and use an isolation tool to prevent implicit dependencies from leaking in from the system.
Examples:
- A Python app should use a requirements.txt file to declare dependencies and a virtual environment to isolate them.
- A Node.js app should use a package.json file to declare dependencies and node_modules to isolate them.
- A Ruby app should use a Gemfile to declare dependencies and Bundler to isolate them.
This applies equally to production and development environments.
Dependency declaration and isolation ensure consistent, repeatable builds and smooth onboarding for new developers.
Twelve-Factor apps should not rely on the implicit presence of system tools. Any required tools should be vendored into the app to guarantee compatibility.
Config
The third factor states that configurations should be stored in the environment, not in the code.
An app's configuration must be stored in environment variables. They are easy to change between deployments, language- and OS-agnostic, and less likely to be accidentally committed to the repository.
Configurations should never be hardcoded as constants, since they vary across deployments. Internal configuration, such as how modules connect, belongs in the code.
Grouping configuration into named environments is discouraged. Instead, use granular environment variables that can be managed independently for each deployment. This model scales cleanly as the app grows and gains more deployments.
Backing Services
The fourth factor emphasizes treating backing services as attached resources, accessed via a URL or credentials stored in configuration.
Backing services include any network-accessed service the app uses, such as databases (e.g., MySQL), message queues (e.g., AWS SQS), or caches (e.g., Redis).
Examples:
- A local MySQL database used in development → mysql://user:pass@localhost/dbname
- A third-party Redis instance used in production → redis://user:pass@redis-host:6379
- A local SMTP server used in development → smtp://user:pass@localhost:25
A twelve-factor app’s code should treat local and third-party services the same way.
Swapping a local service for a third-party one requires changing only the configuration, not the code.
Each backing service is an attached resource that can be connected or replaced without modifying the app itself.
Backing services (image credit: 12factor.net)
Build, Release, Run
The fifth factor emphasizes strictly separating the build, release, and run stages.
- Build stage: turns the code repository into an executable bundle.
- Release stage: combines the build with the current configuration.
- Run stage: executes the app in its environment.
Code must not change at runtime, and each release should have a unique, immutable ID. Builds are created by developers, while runs may happen automatically. Keep the run stage simple to prevent failures when developers are not present.
Build, release, run (image credit: 12factor.net)
Processes
This factor requires running the app as one or more stateless processes in the execution environment. We can summarize this principle using 3 key points:
Processes are stateless and share nothing: any persistent data must live in a backing service such as a database or cache.
Ephemeral storage only: memory or the local file system can be used for temporary, single-use data (e.g., processing a file before uploading it).
No sticky sessions: Storing user sessions in memory violates this principle. Session data should be kept in an external store with expiration, such as Redis or Memcached.
Example:
A web app running three instances behind a load balancer should not keep user sessions in memory. Instead of storing session_id data in RAM, the app saves it in Redis so that any instance can handle the next request seamlessly. Deploying, removing, or replacing instances becomes straightforward, and no matter which instance handles a request, the user experience remains consistent.
Statelessness is a key enabler for effective scaling and automated deployment.
Port Binding
The seventh factor requires exporting services via port binding, while traditional web apps depend on external web servers.
Cloud-Native Microservices With Kubernetes - 2nd Edition
A Comprehensive Guide to Building, Scaling, Deploying, Observing, and Managing Highly-Available Microservices in KubernetesEnroll now to unlock all content and receive all future updates for free.


