01. Codebase
1. The rule: one codebase, many deploys
The whole factor is one sentence: one codebase, tracked in revision control, many deploys. There’s a strict one-to-one correlation between a codebase and an app. One app has exactly one codebase, and that one codebase produces every running deploy of the app. Break the correlation in either direction, too many codebases for one app or too many apps in one codebase, and it stops being one twelve-factor app.
Start with what a codebase is. It’s whatever your version control tracks as a single history: usually one repository, sometimes a set of repositories that share a root commit, the same initial commit they both descend from. The number of repos isn’t the point; the single revision history is. And there’s no such thing as a twelve-factor app that isn’t under version control. Git, Mercurial, Fossil, pick your tool, but the code lives in one tracked history. A folder someone zips up and copies to a server doesn’t qualify.
As the series introduction says, this is the simplest of the twelve factors. It’s also the one every other factor quietly assumes, which is why it comes first. Get this mapping right and the rest have a stable thing to attach to. Get it wrong and factors like config and build-release-run don’t even have a well-defined subject.
2. Codebase, app, deploy: three words that aren’t synonyms
Codebase, app, and deploy are three different things, and the factor falls apart if you blur them. The codebase is the tracked history. The app is the thing that codebase defines: one deployable unit of software. A deploy is a running instance of that app.
The word that trips people up is “deploy,” because it covers more than production. Production is a deploy. Your staging environment is a deploy, and three staging environments are three deploys. Every developer’s local checkout, running on their laptop, is a deploy too. They all run the same app from the same codebase; what differs is where each sits along that codebase’s history. A developer has commits that haven’t reached staging yet and staging has commits that haven’t reached production. Same codebase, different points along it: different versions can be active at once over one shared lineage.
Those history differences are only half of what varies between deploys. The other half is config: production talks to the production database, your laptop talks to a local one. That per-deploy variation is what Config handles, and keeping it out of the codebase is what lets one codebase serve every deploy. The steps that turn a given commit into a running deploy, build then release then run, are Build, release, run.
This framing settles a classic judgment call. Say your app is a web server plus a background worker that chews through a job queue: two things, running as separate processes, often on separate machines. One app or two? It’s one app, one codebase run as two process types across your deploys. Running an app as several process types is the process model, and how far you scale each type is a later factor’s concern; for Factor 1 the point is narrower. Different process types don’t multiply the app count. The web process and the worker come from the same codebase and release together, so they’re one app run two ways, not two apps.
3. Two ways to break the rule
Since the rule is a one-to-one mapping, there are exactly two ways to violate it: more than one codebase per app, or more than one app per codebase. Different mistakes, different fixes.
3.1. Many codebases, one “app”
If what you’re calling one app has multiple codebases, it isn’t one app. It’s a distributed system. Each separate codebase is its own app, and each of those apps can be twelve-factor on its own.
This isn’t a failure, it’s most of modern software. A system built from a handful of services, each in its own repo with its own deploy pipeline, is a distributed system of several twelve-factor apps. Whether to split a system into services at all is a separate design question, one I’ve taken up in comparing monoliths and microservices makes no sense. Factor 1 doesn’t tell you not to build that. It tells you to be honest about the unit: apply the twelve factors per app, not to the amorphous “system” as a whole. The mistake is calling them one app, then wondering why the methodology doesn’t fit. Having many codebases was never the problem. Name each service as its own app and the confusion goes away.
Contrast this with the web-server-plus-worker from the last section. Same-codebase process types are one app; separate-codebase services are separate apps. The codebase count decides it, not the process count or the machine count.
3.2. Many apps, one codebase
The other direction is several apps sharing one codebase, and that’s a genuine violation. The usual culprit is shared code: two apps both need the same utility library, the same models, the same client, so someone drops all of it in one codebase and builds both apps from it.
The fix is to pull the shared code into its own library, with its own codebase, and have each app depend on it through the dependency manager like any other package. Each app is back to one codebase, and the shared code becomes a dependency they declare and pull in. That handoff, from “shared code in a folder” to “declared dependency,” is exactly where Dependencies picks up.
4. Monorepos don’t break Factor 1
“One app per codebase” sounds like it bans monorepos. It doesn’t, and this is the most common real-world confusion about Factor 1. The rule constrains the logical mapping between apps and codebases; a monorepo is a physical packaging choice sitting a level below that. The two are orthogonal.
Read literally, the source’s own definitions seem to rule monorepos out. It calls a codebase “any single repo,” insists there’s “only one codebase per app,” and states “a one-to-one correlation between the codebase and the app.” Chain those together, one repo is one codebase is one app, and a repo holding several apps looks non-compliant on its face. That takes the 2011 wording more literally than it can bear. The “single repo” phrasing reflects the era’s common shape, one repo per app; the load-bearing principle underneath is the logical one-to-one mapping between an app and its codebase, not the physical repo count. The source’s actual violation clause, “multiple apps sharing the same code is a violation,” targets shared code, the section 3.2 case, not the co-location of separate apps. Keeping many apps in one repository on purpose is common at serious scale: Google runs nearly everything from a single monorepo (Bazel, its build tool, is the open-sourced version of the internal Blaze), while tools like Nx and Turborepo exist specifically to manage many apps and libraries in one repo. Read Factor 1 as a claim about logical boundaries, not directory layout: each app maps to one codebase’s worth of history and deploy lineage, and whether ten such apps live in ten repos or one is a packaging decision Factor 1 doesn’t legislate.
A monorepo violates Factor 1 when those logical boundaries dissolve, and there are two ways that happens:
- Apps reach into each other’s internals. App A imports App B’s source directly, by relative path into B’s guts, instead of depending on a versioned library that B publishes on purpose. Now they aren’t two apps sharing a repo, they’re one tangled app pretending to be two: section 3.2 all over again, just inside a single repository.
- No independent deploy lineage. If you can’t deploy App A without dragging App B along, if there’s one release for the whole repo and no app moves on its own, then the apps don’t have distinct deploys. The one-to-one mapping between an app and its deploys is gone.
A monorepo that avoids both, clear per-app boundaries, shared code consumed only through published libraries and each app with its own deploy pipeline, satisfies Factor 1 completely. The repo is just where the code is stored. The boundaries and the deploy lineages are what Factor 1 actually cares about.
5. Why every other factor assumes this one
Factor 1 comes first because every factor after it needs a single, identifiable app with many deploys before it can even be stated. That shape is what the whole methodology is built on.
Look at what the later factors take for granted. Config in the environment (Factor 3) means config that varies per deploy, which presumes you know what a deploy is and that they all share one codebase. Build, release, run (Factor 5) is a pipeline that turns one codebase into deployable releases, and it’s meaningless without the one-codebase premise. Dev/prod parity (Factor 10) is a statement about keeping deploys of the same app similar. Each of them is a claim about “the app” and “its deploys,” and Factor 1 is what makes those two terms well-defined.
That’s why it’s both the simplest factor and a load-bearing one. The rule fits in a sentence, and you can usually check it in a minute. But get the mapping wrong, count a distributed system as one app, or let a monorepo blur into one tangled codebase, and every factor stacked on top inherits the confusion. One codebase, many deploys: settle that, and the rest of the series has a subject.