Skip to content
EL
Contents

What data is, and why we need a database

Should this be a file or a database?

DecisionFoundation4 min read10 min hands-on#fundamentals#storage

The idea in 30 seconds

Files are still the right home for some data: configuration changed through code review, append-only logs, exports, and anything with exactly one writer. Shared state that several processes change, or that you need to query, belongs in a database. The deciding questions are who writes it, how often, and how you will look things up.

On this page

The situation

Your team runs two services: the web app and a background worker. Both need feature flags, the on/off switches that turn features on for some customers. Today the flags are hard-coded. An AI assistant opened a pull request to make them changeable at runtime, from an admin page in either service.

Review taskStore feature flags in a shared JSON file

Pull request: “Runtime feature flags. Both services read and write flags.json on the shared volume, so no new infrastructure is needed.”

# flags.py, used by both the web app and the worker
import json

PATH = "/shared/flags.json"

def get_flag(name):
    with open(PATH) as f:
        return json.load(f).get(name, False)

def set_flag(name, value):
    with open(PATH) as f:
        flags = json.load(f)
    flags[name] = value
    with open(PATH, "w") as f:
        json.dump(flags, f)

Would you approve it? Write the review you would leave.

Your call

When a file is the right answer

Files are not wrong; they are a tool with a narrow sweet spot. A file is a good choice when the data is:

  • Configuration changed through code review. It is read at startup, and changes arrive as commits, one at a time.
  • Append-only. Logs, audit trails and event exports that are written once and never edited.
  • Immutable datasets. A nightly export or a machine-learning training set that is produced once and read many times.
  • Owned by exactly one writer. One process writes; any number of others only read, and the writer replaces the file atomically.
  • Static content that a web server or CDN hands out as-is.

When it belongs in a database

Reach for a database as soon as any of these is true:

  • More than one process changes it. Two writers are enough to need coordination.
  • A crash must not lose or corrupt it. Money, orders, accounts, anything a customer would notice.
  • You need to find things by more than one key. “All orders over ₹5,000 from last week” means a query, not a file read.
  • Several changes must happen together. Debit one account and credit another: all or nothing.
  • Rules must hold. Unique emails, no order for a user who does not exist.

Check yourself

  1. Name three properties of data that make a plain file a good home for it.

    Show answer

    Any three of: changed only through code review, append-only, immutable once produced, exactly one writer, or static content served as-is.

  2. The flags pull request uses a lock around writes but not reads. What can still go wrong?

    Show answer

    Readers can still open the file while a writer has emptied it and not finished writing, and fail to parse it. Atomic replacement (write a temporary file, then rename it into place) is what protects readers.

  3. Why does a single SQL UPDATE avoid the lost-update problem the JSON file has?

    Show answer

    Each UPDATE changes only its own row, not a copy of all the flags read earlier. If two transactions update the same row at once, PostgreSQL makes the second wait until the first commits, then applies the second change on top of the result.

Finished reading?

Saved in this browser only.

Sources

Where each claim on this page comes from.

  1. 1.
    open(2) manual page, macOS
    Primary· O_TRUNC· man 2 open

    Opening a file for writing with truncation empties it before the new contents are written.

  2. 2.
    rename(2) manual page, macOS
    Primary· DESCRIPTION· man 2 rename

    rename() guarantees that an instance of the new name always exists, even if the system crashes in the middle of the operation.

  3. 3.
    flock(2) manual page, macOS
    Primary· DESCRIPTION· man 2 flock

    flock() locks are advisory; they only protect processes that also take the lock.

  4. 4.
    PostgreSQL documentation: 3.4 Transactions
    Primary· §3.4 Transactions

    A transaction bundles several steps into one all-or-nothing operation.

  5. 5.
    PostgreSQL documentation: 13.2 Transaction Isolation
    Primary· §13.2.1 Read Committed Isolation Level

    When a row is already being updated by another transaction, the second updater waits for the first to commit or roll back, then applies its change to the updated row.

Go further

What to read next, and why it is worth the time.

  1. 1.
    flock(2) manual page, macOS
    Primary· man 2 flock

    Short, and the clearest statement of what a file lock does and does not promise.

Applies to PostgreSQL 18. Draft: not yet fact-checked end to end.