top of page

The Twelve-Factor App Part 1

Software developers collaborating on a project
Software developers collaborating on a project

Over a decade ago, Heroku co-founder, Adam Wiggins published the 12-factor app as a collaboration between developers at Heroku to establish best practices for building modern cloud applications. This 12-factor methodology was specifically designed to maximise developer productivity and for application maintainability. In this blog, I intend to guide you through the 12-factor app, offering explanations for each of the various methodologies. In this initial section, I will discuss the first six, followed by a second part to keep the blog concise.


The Twelve Factors

  1. Codebase

  2. Dependencies

  3. Config

  4. Backing services

  5. Build, release, run

  6. Processes

  7. Port binding

  8. Concurrency

  9. Disposability

  10. Dev/prod parity

  11. Logs

  12. Admin processes


I turned to AI (Gemini) to generate a mnemonic for me to remember the 12 factors and here is what it came up with - Crazy Developers Can Build Brilliant Products Promoting Clean Deployment, Delivering Lovely Apps. Reminded me of my Military days where mnemonics were a thing. Now, lets step through each of the factors:


  1. Codebase

    "One codebase tracked in revision control, many deploys." - Working in a team with multiple developers on a single project can lead to conflicts, especially when working on the same file. Git, a free open-source distributed version control system, helps manage this. Platforms like GitHub, GitLab, and BitBucket offer Git-based central repositories, allowing organisations to configure projects, set permissions, and enable teams to track and review changes before updating the codebase. Sharing the same codebase across multiple apps violates the 12-factor principle and should be avoided. Each repository should have separate environments for development, staging, and production.


  1. Dependencies

    "Explicitly declare and isolate dependencies" - A 12-factor app explicitly declares dependencies with version numbers and installs them before running. In Python, dependencies are listed in the requirements.txt file. Dependencies should be isolated, especially if different applications require different versions. Python uses virtual environments to create isolated environments for each application, preventing interference between applications or with the local machine dependencies.


  1. Config

    "Store config in the environment" -

    Configurations that vary by deployment environment (dev, staging, production) should not be hardcoded. Instead, manage them as environment variables to keep your codebase independent of the environment and to protect sensitive credentials from exposure. This approach also enhances portability and scalability which I will touch on later.


  1. Backing services

    "Treat backing services as attached resources" - These are services that your application consumes over the network, whether it be databases, caches, messaging queue, or a file share system. They should be treated as attached resources where individual components are attached to the app via a URL or other locator/credentials stored in Config or securely in a credentials manager.


  1. Build, release, run

    "Strictly separate build and run stages" - This demands a clear, distinct separation between the app's lifecycle stages:

    • Build stage - Compiling code, fetching dependencies and transforming codebase into an executable build artifact e.g a built Docker image

    • Release stage - where the executable artifact with specific config for deployment gets released. Each release is unique, and immutable allowing for easy rollbacks.

    • Run stage - Launches the new release into it's respective environment.

    By separating the build, release and the run phases, we can effectively manage our build artifacts and deployments. Storing our artifacts in a designated location allows us to roll back to previous releases or redeploy a specific release if needed.


  1. Processes

    "Execute the app as one or more stateless processes" - Processes should be stateless and share nothing. Persistent data must be stored in a stateful backing service like a database. Do not assume cached data in memory or on disk is available for future requests, as different processes in a distributed environment may handle them without access to the original memory or filespace.


Look forward

Now that we have covered the first 6 factors, I will stop there and will complete the other 6 factors in the next upcoming blog. Let me know your thoughts in the comments. Is this something that your organisation follows or is there a different approach that your team takes? Keen to know and see you in the next blog!!

Comments


bottom of page