Contents

You Probably Want a Boring Text File

Before reaching for a database, a framework, or an app, check what a plain file already does

Contents

A friend spent a weekend setting up a self-hosted note-taking app, complete with its own database, its own web server, and its own container to keep running, for a personal to-do list she checks maybe twice a day. By the time she finished, she had more infrastructure to maintain than notes to write. A text file in a synced folder would have done the entire job, forever, with nothing to patch, back up separately, or ever migrate off. That’s not a joke at her expense — I’ve made the identical mistake more than once — it’s a pattern worth naming, because the boring option quietly wins more often than the tooling landscape would have you believe.

Why the Plain File Gets Skipped

Advertisement

Nobody sets out to over-engineer a to-do list. The pull towards a “real” solution — an app, a database, a service with a UI — comes from a reasonable-sounding but usually wrong assumption: that structured problems need structured tools, and that a plain text file is somehow the amateur option you graduate away from once you’re being serious about something. In practice the causation runs the other way for a huge range of everyday tasks. A plain text file is durable in a way most purpose-built tools aren’t, portable in a way databases aren’t, and requires precisely zero maintenance, because there’s no service to keep running, no schema to migrate, and no dependency to go unmaintained out from under you.

The tools that genuinely earn their complexity do so because the problem has a property a flat file can’t handle well — concurrent writers who need locking and conflict resolution, relational queries across large amounts of data, access control finer-grained than “who can read this file.” Plenty of the problems people reach for tools to solve don’t have that property at all, and the tool ends up adding failure modes to a task that previously had none: a container that needs restarting after an update, a database that needs its own backup strategy separate from the rest of your files, a web UI with its own login to remember and its own security patches to track. Each of those is a small, individually reasonable cost. Stacked on top of a to-do list that never needed any of them, the total cost dwarfs the problem it was solving.

What a Flat File Actually Gets You

A plain text file inherits, for free, a set of properties that took the rest of the computing ecosystem decades to standardise around, precisely because text files got there first and everything else had to become compatible with them. Every operating system ever built can open one. Every backup tool, every sync service, every version control system treats a text file as its native, best-understood unit of work. grep, sed, awk, your editor’s search-and-replace, and an entire universe of small Unix tools compose against plain text without needing to know anything specific about your particular file’s purpose, because the format doesn’t gatekeep behind an API or a proprietary structure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ cat groceries.txt
milk
eggs
bread
coffee

$ echo "butter" >> groceries.txt
$ grep -c "" groceries.txt
5
$ sort groceries.txt | uniq

That entire interaction — appending an item, counting entries, deduplicating — used off-the-shelf tools that predate most of the apps competing to replace this file, and will very likely still work identically in another twenty years, because the format they’re operating on hasn’t needed to change since it was invented. No install step, no login, no version of the tool to keep patched against a vulnerability — the entire interaction is just the operating system’s own, already-present utilities against a file you can read with your eyes. Compare that against a note-taking app’s proprietary export format, which may or may not still be readable by anything once the app itself is abandoned or the company behind it shuts down its servers.

The Durability Argument, Stated Plainly

Advertisement

This is the part that matters most and gets underrated most. A database-backed app can fail in ways a text file structurally cannot: the app gets discontinued and takes its data format with it; a subscription lapses and the data becomes inaccessible behind a paywall; a schema migration goes wrong and corrupts records nobody thought to back up in a readable form; the company hosting your data shuts down. A plain text file has none of these dependencies, because there’s no service standing between you and your own data — reading it back is just reading a file, in any editor, on any machine, at any point in the future, using tools that have existed for as long as computing itself.

This is also why plain text is the natural long-term storage format even for things that started life somewhere fancier, and why the oldest, most battle-tested corners of the Unix toolchain still assume text as their default currency: pipes, redirection, and the entire small-tools-doing-one-thing-well philosophy all presuppose that the thing flowing between programs is readable text rather than a proprietary binary blob only one specific application understands. A well-run team exports its important notes, its runbooks, its decisions, into plain Markdown files in a version-controlled repository specifically because that format will still be readable in a decade, regardless of which note-taking app is fashionable by then. The fanciness is optional and temporary. The plain text underneath it is the part that survives.

A Config File That Outlasted Three Rewrites of Everything Around It

I have a plain text file on my own home server, tracking which devices get which static IP reservation, that predates three separate rewrites of the network management tooling sitting around it. Each rewrite swapped out the fancy layer — a different dashboard, a different automation script, a different container orchestrating the change — and each time, the actual source of truth stayed the same flat file, because nothing about switching dashboards required migrating the data itself; the new dashboard just learned to read the old file. If that information had instead lived inside whichever dashboard’s own database was fashionable at the time, each rewrite would have needed a genuine data migration, with its own chance of losing or corrupting entries in the process. The boring file didn’t just survive the rewrites — it’s the reason the rewrites were low-stakes at all, because the one thing that actually mattered was never at risk of the new tool’s teething problems.

This is a general pattern worth watching for in your own setup: whatever holds your actual source of truth is the thing you should be most conservative about, and a flat, human-readable file is usually the most conservative choice available, precisely because reading it back never depends on a specific piece of software still existing, still being compatible, or still being maintained.

Where a Flat File Genuinely Isn’t Enough

None of this is an argument that files beat every tool at everything — that would be its own kind of overcorrection. A shopping list, a personal to-do list, a running log of decisions, a simple configuration a handful of scripts read, notes for yourself: a flat file, ideally version-controlled or synced, is more than sufficient and meaningfully more durable than the app you’d otherwise reach for.

Concurrent multi-user editing is the clearest case where a plain file starts to strain: two people editing the same file at the same time, with no locking mechanism, risk silently overwriting each other’s changes, and a flat file has no built-in concept of merging concurrent edits the way a real-time collaborative document does. Large amounts of structured, queryable data is another — searching a ten-line grocery list with grep is instant and trivial; running arbitrary relational queries across tens of thousands of structured records is exactly the job a database was built for, and reimplementing that with shell scripts against a giant flat file is its own quiet form of over-engineering, just in the opposite direction. Fine-grained access control is a third — a flat file’s permission model is whoever can read the file can read everything in it, which is fine for a personal list and inadequate the moment different people need to see different subsets of the same information.

The judgement call is practical rather than ideological: this piece argues against reaching for a database or an app by default, before checking, rather than against ever using one. It’s checking, honestly, whether your actual problem has one of these specific properties before reaching for the tool that solves it, rather than reaching for the tool because it’s the fashionable default.

Worth naming explicitly: there’s a genuine middle ground between “one flat text file” and “a full client-server database,” and it’s worth knowing it exists before assuming the only escalation path from a text file is something as heavy as a hosted database server. SQLite is a complete relational database that lives in a single file, needs no separate service running, and still gives you real queries, indexes, and transactional guarantees once a flat file’s grep-and-hope approach genuinely stops being enough. It keeps almost everything that makes plain text appealing — a single portable file, no server to maintain, easy to back up by just copying it — while adding the structured-query capability a flat file lacks. For anything that’s outgrown a text file but doesn’t remotely need a dedicated database server, it’s very often the actual right next step, rather than jumping straight to the heaviest available option.

Troubleshooting: Checking Whether You Actually Need More

A quick set of honest questions catches most premature tool adoption before a weekend gets spent on it. Will more than one person ever need to edit this at the same time, in a way that needs real conflict resolution rather than “whoever saves last wins”? If not, the concurrency argument for a database-backed tool doesn’t apply to you.

Will you ever need to query this data in ways grep, sort, and a text editor’s search genuinely can’t express — filtering across thousands of records by several criteria at once, say? If the honest answer is “no, I just want to read a short list,” the query argument doesn’t apply either.

Does this data need different access levels for different people, where some content should be hidden from some viewers? If it’s just you, or a small group who’d see all of it anyway, access control isn’t actually a requirement you have, whatever the tool’s marketing implies.

If none of these apply, and you still find yourself reaching for an app, ask the plainest possible version of the question: in five years, will you rather be reading a text file in whatever editor exists then, or hoping a specific app is still maintained, still installed, and still able to open a format nobody else’s software understands?

Is the Boring Option Worth Choosing?

For a genuinely large share of the small, personal, low-concurrency tasks that fill up a typical week, yes, overwhelmingly, and the honest test is simple: if you can’t articulate a specific property your problem has that a flat file lacks, you don’t yet have a reason to reach past it. The plain text file isn’t the fallback option for people who haven’t found the “real” tool yet — for a lot of these jobs, it is the correct, durable, low-maintenance answer, and the tools competing to replace it are mostly solving problems you don’t actually have, at the cost of a dependency you didn’t need. Reach for the database, the app, or the framework when your problem genuinely has the property that justifies it — real concurrency, real queries, real access control — and reach for a text file everywhere else, because it will still open, unmodified, in whatever you’re using to read files a decade from now. If this argument resonates, SQLite: the database you already have and probably underuse covers the natural next step once a flat file genuinely stops being enough, and Bash: the good, the bad, and the ugly is a fair look at the toolchain that makes plain text files so cheap to work with in the first place.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.