
Is a 2011 manifesto still relevant in the modern cloud-native world?
In November 2024, the Twelve-Factor App methodology was open-sourced, inviting community-driven updates to help it evolve with modern cloud-native practices like Kubernetes, GitOps, and workload identity. This shift enables continuous adaptation and ensures the methodology remains practical and up-to-date.
Today, we’ll walk through all 12 factors and assess their relevance in 2025. Spoiler: they’re more important than ever.
I. Codebase
A twelve-factor app uses a single codebase tracked in version control, with many deployments. Today, teams commonly work from a single main branch as the source of truth. Developers create “feature” or “fix branches”, open a pull request to main, and trigger deployments from there—each going to a different environment like dev, staging, or production. This ensures consistency, minimizes confusion, and supports CI/CD pipelines.

No matter how many environments you deploy to, you maintain just one codebase—as it should be.
II. Dependencies
Your application must declare all dependencies explicitly, ensuring anyone can replicate your environment with a single command.
Different languages have their own tools for this:
JavaScript: package.json / package-lock.json / yarn.lock
Python: requirements.txt
PHP: composer.json
Go: go.mod
These tools lock dependency versions to guarantee consistency across development, staging, and production. No more “it works on my machine” headaches—every team member runs the same dependencies.
This practice is critical for reproducible builds and reliable deployments.
III. Config
Configuration settings can include anything that differs between environments, such as a database URI, an API endpoint, or an API secret. You should not set up configuration settings directly in your code. Instead, you need a separate way to configure your app.
A common approach is using environment variables because they allow you to configure your app without exposing sensitive information.
For example, if you have a secret key for accessing the Stripe platform, you should not include it in your code because it would be exposed on Git for all developers. You should not store it in a file within the application build either, as someone could access the build and extract the secrets.
The safest way is to use environment variables because they remain in memory and are only accessible while the application is running. Once the server shuts down, the secret disappears.
How do you store secrets in environment variables? That depends on the cloud provider you're using. Most cloud services today offer Secret Managers, which automatically export secrets to environment variables when an application is deployed.
For local development, you can use a .env file. Various libraries help retrieve configurations from environment variables or a .env file. Alternatively, you can manually export the .env file to your local environment variables before starting development.
Never commit the .env file to your Git repository. Always add it to .gitignore.
By following this practice, you keep your configuration settings separate for different environments and ensure the security of your secrets.
IV. Backing services
Treat backing services as attachable resources. These are services your app consumes over the network, like:
Datastores: PostgreSQL, CouchDB, Firebase
Messaging/Queueing Systems: RabbitMQ, Beanstalkd
SMTP Services for Email: Postfix
Caching Systems: Redis
Third-Party APIs
Your app should be able to switch services without code changes. For instance, moving from a staging PostgreSQL instance to a production one should only require changing an environment variable.
This makes your architecture flexible, resilient, and easier to manage across environments.

V. Build, release, run
As you may have noticed, the code and the environment are separate. This section explains how to put everything together and run your app.
Build Stage: Converts the code repository into an executable bundle (the "build"). The process differs by language:
JavaScript: a dist directory
Go/Rust: a compiled binary
Docker: an image with all dependencies installed
After this step, you have a version that can be deployed anywhere and is linked to a specific commit in your code repository.
Release Stage: Combines the build version with the configuration of a specific environment (e.g., staging or production). Configuration settings are retrieved from a Secret Manager or a configuration file.
Run Stage: Executes the application in its designated environment.
With this approach, you can deploy your app at any time to multiple environments. You don't need to rebuild it for every environment—just create a new release and deploy it.

VI. Processes
Twelve-factor apps are designed to be stateless. Any data that needs to be persisted must be stored in a stateful backing service, such as a database.
Always treat your app as a stateless process. That means:
Do not save files locally.
Do not store critical data in memory.
This ensures that if a process stops, a new one can pick up the next request seamlessly.
Twelve-factor apps assume that anything cached in memory or on disk will not be available for future requests. This allows for easy scalability—when demand increases, you can simply create more processes.
VII. Port binding
Export services via port binding.
Many web apps run inside a web server container. For example:
PHP apps often run as modules inside Apache HTTPD.
Java apps might run inside Tomcat.
Node.js apps open a port to receive requests.
The twelve-factor app should be self-contained and not rely on runtime web server injection. Instead, it should bind to a port and listen for incoming requests.
To achieve this, you can use Docker containers to bundle the application with its web server setup.
VIII. Concurrency
Since twelve-factor processes are stateless, you can run multiple instances of your app as needed. For example, you can:
Run multiple web processes
Run separate worker processes to handle background jobs
This enables:
Scalability: Easily handle high traffic loads.
Fault isolation: One process failing won’t affect others.
Efficient resource utilization: Better CPU and memory distribution.
The process model enables different workloads (e.g., web requests vs. background jobs) to be handled separately, avoiding contention and improving fault isolation.
IX. Disposability
Processes should be disposable, meaning they can be started or stopped instantly. This allows for:
Fast scaling
Quick deployments
Robust production releases
Apps should be designed to handle shutdowns gracefully and recover pending work when restarted.
X. Dev/prod parity
Keep development, staging, and production as similar as possible. Continuous deployment helps achieve this by enabling frequent releases.
For local development, use the same services as production. If production uses PostgreSQL, don’t use MySQL locally—some features may differ.
To ensure consistency, use Docker containers with a docker-compose.yaml file to run the same external services locally.
XI. Logs
Treat logs as event streams.
Do not save logs in files or memory.
Applications should only generate logs—not manage their output.
Use external log aggregation services to collect and analyze logs.
XII. Admin processes
Admin processes (e.g., database migrations) should be treated as one-off processes that run in the same environment as the app.
They should:
Use the same codebase and configuration
Be included in the application codebase to prevent synchronization issues
Conclusion
Since the Twelve-Factor App methodology was proposed, all factors remain relevant today. It has become a best practice for building modern applications.
Recent updates include:
Workload Identity: A proposal was introduced to add a new factor focusing on workload identity, aiming to enhance security practices by ensuring that applications can securely identify themselves to other services.
Expanded Configuration Management: Updates to the configuration factor now accommodate the use of mounted volumes, providing more flexibility in handling configuration data across diverse cloud environments.
Enhanced Logging and Telemetry: The logging factor has been expanded to encompass telemetry, aligning with contemporary observability practices that include metrics, tracing, and structured logging to offer deeper insights into application behavior.
Addressing the 'Shift Left' Movement: The methodology now incorporates strategies to balance the 'shift left' approach, which integrates quality and security earlier in the development cycle, by clearly defining roles and responsibilities to reduce developer cognitive load.
Integration with GitOps Practices: Twelve-Factor principles have been updated to support GitOps methodologies, promoting declarative configurations and automated deployments to enhance consistency and reliability in application delivery.
Alignment with Modern Cloud-Native Patterns: The principles have been refined to better align with contemporary cloud-native architectures, including containerization and orchestration, facilitating seamless deployment and scaling in platforms like Kubernetes.
Emphasis on Developer Experience: The methodology now places a stronger focus on improving developer workflows by simplifying application onboarding, ensuring development environments closely mirror production, and providing clear documentation and examples.
These updates ensure that the Twelve-Factor App methodology remains a relevant and practical guide for building scalable, maintainable, and secure cloud-native applications in 2025 and beyond.
For more details, visit: https://12factor.net/
Sources:
Apr 15
6 min read