A Problem With Single-File Codebases

4 min read Original article ↗

Written at 2025-07-16


Here’s a tweet from Tsoding (a recreational programmer who creates cool videos);

Stop obsessing over splitting code into files. I end up grepping codebases anyway. I literally don't care where you put your functions. miniaudio.h is a single file with 92k LOC and it's fine. File is an OS construct anyway. pic.twitter.com/4zLXGrXEzA

— Тsфdiиg (@tsoding) February 14, 2025

I think he has a point. If I had to choose between a codebase with satellite-style files and a single-file codebase, I’d probably pick the latter.

Especially with C, I can understand the benefits of having a single-header library. It makes distributing and integrating your code into other codebases much easier. But that’s mostly a C thing (or perhaps something that applies to other languages without package managers where you need to vendor dependencies manually as well).

I also think you can work just as efficiently in a single file as you would in a repo split across many files. It’s definitely possible, especially if you’re someone like Tsoding.

Again, I don’t like seeing too many files clustering around like small satellite particles. I think excessive use of new files is often correlated with some kind of boilerplate being followed (which is very common in Java, C#, or even C++ communities) and with code that’s harder to trace. That being said, I think, taking this idea of “not splitting pieces of code into separate files” can also be nearly as bad as those satellite files making it harder to trace the code as you need to jump between files all the time.

The Problem

I think the main problem with both single-file and satellite-style codebases is that it’s far easier for the person who wrote them to operate on them than it is for others trying to get adjusted. That’s because the original author already has an idea of what kinds of functions exist in the codebase, so they can just grep for things and navigate easily.

Reading a codebase when you already know what exists beforehand, and reading one when you have no idea what you’re going to encounter until you read it, is a HUGE difference. It’s easy to overlook this and assume your code is simple to understand, especially if you’re the one who wrote it recently.

Let’s say you’ve just joined a backend project and you are expected to develop a new endpoint. Compare a system where files are organized hierarchically according to their relevant topics (db, api, routes, entrypoint) with a system where there is a single, very long file. Which one do you think would be faster for you to figure out which places to start trying to understand for the feature/thing you particularly are interested in?

image

If you go with the first approach, you’ll likely need to skim through the entire file to figure out where to add your new feature. With the second approach, it’s usually more obvious where to look first. You might even be able to implement the feature without touching any of the other files. In a way, splitting related pieces of code into different files also helps signpost the structure of your project.

Splitting your codebase into multiple files can also reduce the likelihood of version control conflicts and allow AI tools to index and analyze your code more effectively.

So, I agree with Tsoding that we shouldn’t obsess over splitting our code into separate files. But I don’t think the opposite extreme, putting everything into one large file whenever possible, is necessarily better either. There are real benefits to separating code in certain places.

Personally, I tend to split code into different modules or files once a file starts to feel overwhelming. I think of it somewhat like a table of contents in a book: it’s a form of signposting. And I believe signposting can be helpful not just in programming, but in reading and understanding things in general. Imagine having to read a textbook without titles, chapters, or any other structure.

Files may be “OS-level constructs anyway,” but so are many other constructs from different domains that are useful to us.