Development Basics

What is a Codebase? Key Concepts You Should Know

What is a Codebase? Key Concepts You Should Know

GitHub’s Octoverse 2025 report lists 630 million repositories. That number says little about how many codebases exist, because platforms count repositories, not codebases. One software system’s code can span several repositories, or share a single one with other projects.

Strip it down and the codebase is the source code plus the files around it (configuration, tests, build scripts, documentation) that build, run and maintain one software system. Development teams track those files in version control. The compiled product sits outside the set.

What is a codebase?

YouTube player

Ask around and the scope changes with every person. Source code, configuration, tests, build scripts and documentation all count, as long as they serve one program, component or system. The compiled product doesn’t.

Small apps and libraries are usually one repository with one history. A bigger product can be split into several repositories, and a team will still call the lot its codebase. Google’s company-wide tree in a single repository is the far extreme.

Most teams keep the codebase tracked in source control, but the definition doesn’t require it. The Twelve-Factor methodology treats tracking as a rule for well-run apps, which makes it a standard to meet and not part of what a codebase is.

A folder of untracked files is still a codebase. Just an unsafe one to edit.

What a codebase contains and what stays out

Source files, configuration files, build scripts, tests, dependency manifests and documentation all belong in the tree. Anything the build or the editor can recreate stays out.

Files that belong in the codebase

  • The source files themselves, in Python, Java, JavaScript or whatever the project runs on
  • Configuration files, usually YAML or JSON, that change behavior per environment
  • Build scripts that turn source into a runnable program
  • Unit and integration tests that check behavior after every change
  • Dependency manifests (package.json for npm, pom.xml for Maven)
  • The README, license and any architecture notes

The manifest belongs in the tree. The libraries it points to do not, because npm and Maven download them on demand.

Files that stay out of it

YouTube player

Generated output has no place in the tree. That covers compiled binaries and other build artifacts, installed packages and editor swap files.

Teams enforce the boundary with a .gitignore file. Git’s documentation describes it as a list of intentionally untracked files, and projects normally fill it with patterns for files the build generates.

Vendored third-party code is the gray area. Copying a library’s source into the tree makes it part of the codebase, along with the upkeep.

Google’s codebase held roughly one billion files in January 2015, but only nine million were unique source files, according to Potvin and Levenberg (Communications of the ACM, 2016).

File count and source count are different measurements. At Google the gap is more than a hundredfold.

Codebase vs repository, source code and project

The codebase is the files as a whole. A repository is only where they’re stored and versioned, source code is the human-written slice, and a project is all the work wrapped around the lot.

TermWhat it coversRelation to the codebase
CodebaseSource code plus configuration, tests, build scripts, docsThe whole set
RepositoryVersioned storage with full change historyHolds a codebase or part of one
Source codeHuman-written instructions onlyA subset
ProjectGoals, people, schedule and the productProduces and relies on it

The repository is the version database behind the files, holding every commit, branch and tag, whether it’s a Git repository or a Subversion equivalent.

The Twelve-Factor methodology draws the strictest line. Under Subversion, one repository is one codebase, and under Git the unit is the set of repositories sharing a root commit. A product built from several such codebases counts as a distributed system, and each part is its own app.

A 2019 GitLab blog post splits the terms by age instead, describing the repository as the home of archived code and the codebase as the code under active development. The Twelve-Factor definition has no such rule and ties the two terms together by structure.

GitLab’s own history fits the structural reading. It ran its Community and Enterprise editions as two codebases and announced in 2019 that it was moving to a single one.

My rule of thumb: say codebase for the files as a whole, repository for where they live, and source code only when configuration, tests and docs are excluded on purpose.

How a codebase is stored and tracked

A version-controlled repository records every change as a commit and keeps parallel work on branches. For shared access it usually sits on a host like GitHub or GitLab.

Version control and history

YouTube player

Version control comes in centralized and distributed flavors. Subversion keeps one central repository. Git and Mercurial give every developer a full copy.

In a distributed system like Git, a clone mirrors the whole repository with its history, so every clone doubles as a backup (Pro Git).

Every commit is a recorded change carrying an author, a timestamp and a message. Branches let work run in parallel and merge back later, and when two edits hit the same lines you get a merge conflict that a person has to settle by hand.

Centralized systems have one weakness. The server is a single point of failure, which Pro Git calls the most obvious downside.

Reviews, permissions and ownership

Access rules decide who gets to change the codebase, and GitHub handles that through branch protection and a CODEOWNERS file (GitHub Docs, as of October 2026).

Branch protection sends pushes to a protected branch through a pull request, which has to collect the required number of approving reviews.

The CODEOWNERS file maps paths to people or teams, and branch protection can require a review from those owners before a merge. It has limits, though. The file lives in the root, docs/ or .github/ directory and applies to one branch only, so review requests fire only when it sits on the pull request’s base branch.

Together the two settings turn code review from a habit into a rule.

Open source and proprietary codebases

Public repositories get the attention, but most of the work happens in private. GitHub’s Octoverse 2025 found that 81.5% of contributions went to private repositories, even though 63% of all repositories were public.

Open source codebases can be read by anyone, and outsiders contribute through pull requests that maintainers review. In a proprietary one, access is limited to named people and teams, though the same review rules apply inside the company.

Visibility changes who can read and who can merge. The structure of the codebase stays the same.

Monorepo or polyrepo: choosing a codebase structure

YouTube player

A monorepo puts many projects in one repository, and a polyrepo gives each project its own. Which one fits comes down to how much code your teams share and how much tooling the company can pay for.

By the Twelve-Factor definition, a monorepo is one codebase no matter how many apps it holds, so the two terms overlap without matching.

Directory layout and modules

Structure starts inside the repository, long before the monorepo question comes up.

The top level usually holds a README, a license, build and config files, then folders such as src, tests and docs. A module is a folder or package that exposes a small public surface and hides the rest. Naming should follow one convention per file type, enforced by a linter instead of memory.

Group by feature (billing, accounts) and not by layer (controllers, models) as soon as the project has more than one real domain. A change to billing then touches one folder instead of four.

Monorepo vs polyrepo

A 2018 ICSE paper, “Advantages and Disadvantages of a Monolithic Repository” (Jaspan et al.), surveyed engineers who had worked in both models and checked their answers against developer tool logs. Code visibility and central dependency management favored one repository, as did automatic updates of dependent code. Toolchain freedom, access control and stability went to the many-repository side.

FactorMonorepoPolyrepo
Cross-project changeOne commit updates an API and its callersSeparate pull requests per repository
Code discoveryOne search covers all codeSearch must span repositories
DependenciesManaged centrallyManaged per repository
ToolchainShared, set centrallyChosen per team
Access controlNeeds path-level rulesSet per repository

GitHub’s repository architecture guidance points monorepo teams to build automation tools such as Bazel and Nx, and polyrepo teams to scripts that run tasks across repositories.

On the monorepo side, engineers can find APIs to reuse and examples of how to call them, and dependent code updates in step with an API migration. The downsides are tooling cost that grows with size and circular dependencies that slip in unnoticed (GitHub guidance).

Polyrepo teams pick their own toolchains and can restrict access per repository. Any change that crosses repositories needs orchestration, and that’s the part people underestimate.

How to decide

A monorepo makes sense when shared libraries change weekly and the projects release together, as long as one team can own the build tooling.

If teams ship on separate schedules and share little code, or if you need hard access boundaries, a polyrepo fits better.

Melvin Conway’s 1968 Datamation paper, the source of Conway’s law, explains why the second case is common. Organizations that design systems produce designs that copy their own communication structures. Draw repository lines where teams already talk to each other less.

Teams running a microservices architecture often follow that line and give each service its own repository.

A monorepo can strain at scale. Microsoft moved the Windows source from more than 40 depots in Source Depot into one Git repository and had to add a virtual file system, GVFS, to keep Git usable (Brian Harry, Microsoft, 2017).

Meta reached the same wall and built Sapling, because public version control systems could not handle a repository of its size (Meta Engineering, 2022).

Both routes needed custom tooling beyond stock Git. A single app with one team never gets there: one repository is the default and the right answer.

How large a codebase gets and how to measure it

YouTube player

Size gets counted as lines of code, file count, language mix or disk size, and the line count swings with whatever the counter chooses to skip. Lines usually get split into source, blank and comment lines, while file count takes in every tracked file, docs and config included. Disk size is really two numbers, the working tree and the full history, and they differ widely.

The cloc tool reports blank, comment and code lines per language in separate columns, and it can diff two versions of a codebase.

Some numbers for scale:

  • Windows is about 3.5 million files and roughly 300 GB as a Git repository (Brian Harry, Microsoft, 2017)
  • Linux 6.13 comes to 39,819,522 lines, counting comments, blank lines, documentation and build files (Heise, January 2025)
  • Linux history holds 1.4 million commits in 5.5 GB, against a 1.7 GB current source tree (git-scm.com, 2025)
  • Meta’s internal repository has tens of millions of files, commits and branches (Meta Engineering, 2022)

The Linux number shows the trap. It counts comments, blank lines and documentation, and a build for one machine skips most of the driver code.

Heise adds that deleting drivers would shrink the count while hurting users, so lines of code measure volume, not quality.

The Linux figures also separate two sizes people mix up. History is the larger share there, so measuring only the checkout understates what a clone carries.

What makes a codebase healthy?

Healthy mostly means you can change the code quickly without breaking things. Tests catch the breakage and automated checks run on every change, and old code shouldn’t get harder to read each year.

Technical debt and legacy code

YouTube player

Ward Cunningham coined the debt metaphor in a 1992 OOPSLA report, writing that “shipping first time code is like going into debt.” In his telling, a small debt speeds development when a rewrite pays it back soon, and every minute spent on not-quite-right code is interest on what stays unpaid.

That meaning is narrower than the way people now use technical debt for any messy code. Cunningham’s own 2009 follow-up describes the metaphor as a defense of refactoring and corrects common misreadings.

SonarQube turns debt into time: the sum of remediation effort for every maintainability issue, shown in days of eight hours (SonarQube Server 2025.6 docs).

That figure prices the repayment. An O’Reilly Radar essay argues the real measure is the cost of owning the debt, meaning the extra time it adds to all past, present and future work.

Legacy code has no single definition. Some people use it for anything inherited from someone else, the dictionary sense that Feathers sets aside. Michael Feathers himself defines it as code without tests, in his 2004 book, and Eli Lopian’s version, reported by SAP Press, is code developers fear changing.

Diomidis Spinellis, reviewing Feathers’ book, called the tests-based definition idiosyncratic and noted that no empirical evidence existed on retrofitting unit tests onto old code.

Quality signals

Test coverage, static analysis results, the state of the continuous integration build and how stale the dependencies are tell you more than any style score.

SignalWhat it showsExample tool
Test coverageShare of code that tests executeSonarQube
Static analysisRule violations and likely bugsESLint, SonarQube
Build statusWhether tests pass on every changeCI pipeline
Dependency freshnessOutdated or vulnerable librariesDependabot

SonarSource’s default Sonar way quality gate demands zero new issues and at least 80% test coverage on new code.

A line that runs under a test is not a line that is checked, so treat coverage as a floor.

Applied to a whole legacy project, the same gate fails on day one. SonarSource’s own guidance, Clean as You Code, applies it to new and changed code only and lets the old code improve as it gets touched.

Refactoring without breaking the build

Refactoring changes the structure of code without changing what it does, and tests are the proof of the second half.

Good code refactoring moves in steps small enough that a red test points at the last edit. Feathers’ method for untested code starts with characterization tests that pin down current behavior, then moves to edits.

No tests yet? Write characterization tests around the area before changing it. Where they exist, work one module at a time and keep the build green after every step.

Cunningham’s 1992 report repays debt with a rewrite, and that works when the module is small and its behavior is understood. A rewrite without tests is the same gamble at larger scale.

How to learn an unfamiliar codebase

YouTube player

Start with the running application, not the source files.

  1. Read the README and any architecture notes, then follow the build instructions until the app runs locally.
  2. Run the test suite and note what fails on a clean checkout.
  3. Read the tests for the area you will change. They show intended behavior faster than the implementation does.
  4. Check the history of that area: who changed it, when and why.
  5. Trace one feature or request from entry point to database.
  6. Ship one small change through code review.

The git log output for a file shows how it reached its current shape.

Git blame adds the author of each line, which tells you who to ask. A CODEOWNERS file, when the repository has one, names the owners outright.

In a large tree, code search finds callers faster than browsing folders. Sourcegraph and the search box on a hosting service both do this across repositories.

Documentation lags the code, so when it disagrees with the tests or the running app, believe the tests and the app. Reading every file before touching anything is the other classic mistake, and skipping step 2 hides a red build that then looks like your own bug.

Codebase FAQ

Is it codebase or code base?

Both spellings appear in print and mean the same thing. Technical documentation, including the Twelve-Factor methodology, writes it as one word, so pick that form and keep it consistent across a project.

Does codebase mean the same thing in blockchain and machine learning projects?

Yes. The term still names the source and supporting files of one project.

Open source blockchain projects publish theirs so outsiders can audit the code, and machine learning projects count training scripts and notebooks as source files.

How does a codebase become running software?

A build tool reads the build scripts and dependency manifests, then compiles or bundles the source into a runnable artifact such as a binary or a package.

Interpreted languages skip the compile step but still install their dependencies before deployment.

Do you still need a backup if the codebase is on GitHub?

Yes. Every clone of a Git repository holds the full history, but not the hosting service’s pull requests, issues or wikis.

Keep a mirror clone on separate infrastructure and export the platform data you cannot afford to lose.

Can AI tools explain an unfamiliar codebase?

Yes, for orientation. Assistants such as OpenAI’s Codex can map how a request flows through the modules and name the next files to read.

They only see what they are given, so check every claim against the tests and the running app.

Where to Start When a Codebase Has No Safeguards

Start with a README that gets the codebase running on a clean machine, since the test suite, pull request checks and developer onboarding all depend on a first working build.

After that come tests around the next area you plan to change, then required review on the main branch. Tests go first because reviewers cannot verify behavior without them, so approvals would rest on guesswork.

The cost is slower early merges, because every change now waits for a passing build and a reviewer.

The order holds for one team. When two or more teams commit to the same repository, assign owners per path before adding more reviewers (position verified October 2026).

Wider software development best practices cover what to add after these three.

Bogdan Sandu

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.