How to Design an Application That Runs Easily on Any Cloud?
The 12 Factors for Applications That Run Smoothly on the Cloud
Ever wondered how to build an application that runs seamlessly on any cloud without issues? The answer lies in the 12-Factor App, a set of principles developed by engineers at Heroku after deploying thousands of applications. These principles help you create flexible, scalable, and easy-to-manage applications. In this blog post, we'll explain the 12 factors simply, with practical real-world examples.
I. Codebase
One Principle: Each App Has a Single Repository
Every application should have a single Codebase tracked in a version control system (like Git). If an application uses multiple repositories, it’s considered a Distributed System, where each component is a separate service.
Why?
Simplifies tracking changes.
Makes error management easier.
Supports Continuous Deployment independently.
Practical Example: If you have a web app and an API, keep each in its own repository, not in a single Mono Repo.
Note: With all due respect to Mono Repo fans, the 12-Factor App prefers separation for flexibility 😊.
II. Dependencies
Declare and Isolate Dependencies Clearly
Every application should explicitly declare its dependencies in a separate file, like requirements.txt for Python or package.json for Node.js. Avoid uploading dependency files to the repository using .gitignore.
Why? Keeps the code clean and allows any application version to be installed in any environment without issues.
Practical Example: For Python, list all required libraries in requirements.txt. For Node.js, use package.json. This ensures easy setup in any new environment.
III. Config
Store Configuration in Environment Variables
Any configuration that varies between environments (e.g., database connection strings or API keys) should be stored in Environment Variables, not hard-coded in the application.
Why?
Simplifies changing settings without modifying code.
Enhances security by keeping secrets out of the code.
Ensures compatibility across environments.
Practical Example: If your Development environment uses a local database and Production uses a cloud database, you only need to update the Environment Variables—no code changes required.
IV. Backing Services
Treat Backing Services as Attached Resources
Any external service an application depends on (e.g., database, cache, or external API) should be treated as an Attached Resource.
Why? If you switch services (e.g., from a local MySQL to Amazon RDS), you only need to update the configuration, not the code.
Practical Example: In development, you might use a local MySQL. In production, you might use a managed MySQL like Amazon RDS. The app works in both without code changes.
V. Build, Release, Run
Separate Build, Release, and Run Stages
Continuous Deployment in the 12-Factor App consists of three independent stages:
Build: Compile the application with all dependencies and assets to produce a ready Artifact.
Release: Deploy the Artifact to the target environment.
Run: Launch the new version and route traffic to it.
Why? Separation ensures that errors in one stage halt the process, making the system Fail-safe.
Practical Example: If an error occurs during the Build stage, no version is deployed to Production, reducing issues.
VI. Processes
Run the App as Stateless Processes
Each process in the application should be Stateless, meaning it’s independent and doesn’t rely on other processes to handle requests.
Why? Allows requests to be distributed to any available process without conflicts, enabling scalability.
Practical Example: If your app uploads files for processing, any available process can handle the request. If you use PHP Native Sessions (Sticky Sessions), you’ll need a Shared Cache Layer like Redis to remain Stateless.
VII. Port Binding
Export Services via Port Binding
The application should be Self-contained and accessible through a single port, without needing an external web server.
Why? Makes the app independent and easy to run on the cloud.
Practical Example: With Node.js and Express or Python and FastAPI, the app itself acts as the web server. Using PHP with an external server like Apache is less ideal per the 12-Factor App 😊.
VIII. Concurrency
Scale Out Using the Process Model
In the 12-Factor App, Processes are the primary unit. As workload increases, the cloud spins up new processes (Horizontal Scaling).
Why? Simplifies and streamlines scaling.
Practical Example: If user traffic spikes, the cloud automatically launches additional processes to distribute the load.
IX. Disposability
Design for Fast Startup and Graceful Shutdown
The application should start quickly and shut down Gracefully when receiving a termination signal.
Why? Maintains the stability of backing services and allows resource reuse.
Practical Example: When the cloud terminates a process, the app completes current requests and closes connections safely.
X. Dev/Prod Parity
Keep Development and Production Environments as Similar as Possible
Ensure development and production environments use similar backing services.
Why? Differences between environments can cause issues in production that aren’t visible in development.
Practical Example: Using SQLite in development and PostgreSQL in production might cause minor issues. Use the same service in both environments if possible.
XI. Logs
Treat Logs as Event Streams
The application shouldn’t manage logs itself. Instead, it writes events to stdout, and the cloud handles log management.
Why? Simplifies centralized log management via a Message Queue or Cloud Logging service.
Practical Example: The app writes logs to stdout, and the cloud forwards them to a service like AWS CloudWatch.
XII. Admin Processes
Run Administrative Tasks as One-Off Processes
Administrative tasks (e.g., database migrations) should be treated as One-off Processes executed by the cloud when needed.
Why? Keeps admin tasks organized and easy to execute.
Practical Example: Run a database migration as a command in the cloud environment.
Conclusion
The 12-Factor App is designed to simplify Continuous Deployment, reducing the time from development to production from weeks to hours. These principles empower engineers to build and deploy applications independently, without waiting for Sysadmins or Release Managers.
If your company still uses outdated methods, share this post with them—the world is much easier with the 12-Factor App! 😊