Skip to content
DevelopmentBeginner7 min read

What Is a Database?

A database is a program whose entire job is storing data so it survives, stays consistent, and can be found again quickly.

Written by Daksh BathlaFounder — Technology, Product & Business
Published 3 June 2026 · Updated 1 August 2026

Why not just a file?

You could store data in a text file. It works until two things happen at once. Two users saving at the same moment overwrite each other. A crash halfway through a write leaves a half-file. Finding one record means reading the whole thing. And nothing stops you writing a customer with no email address.

A database is a program that has solved all four, carefully, over decades. That's what you're adopting — not storage, but the guarantees around it.

  • Durability — once it says saved, it survives a power cut mid-write
  • Concurrency — many readers and writers at once without corrupting each other
  • Integrity — rules the data must satisfy, enforced by the database rather than by every developer remembering
  • Speed at scale — finding one row among millions without reading all of them

Relational databases

The most common kind. Data lives in tables — rows and columns, like a spreadsheet with rules — and tables reference each other by id. PostgreSQL, MySQL, and SQLite all work this way, and they're queried with SQL.

schema.sql
CREATE TABLE customers (  id         SERIAL PRIMARY KEY,  email      TEXT NOT NULL UNIQUE,  name       TEXT NOT NULL,  created_at TIMESTAMPTZ NOT NULL DEFAULT now()); CREATE TABLE orders (  id          SERIAL PRIMARY KEY,  customer_id INTEGER NOT NULL REFERENCES customers(id),  total_cents INTEGER NOT NULL,  placed_at   TIMESTAMPTZ NOT NULL DEFAULT now());

Read the constraints, not just the columns. `NOT NULL` means a row without it is rejected. `UNIQUE` means two customers can't share an email. `REFERENCES` means an order can't point at a customer who doesn't exist. Those three lines prevent a category of bug that would otherwise live in your application forever.

query.sql
SELECT c.name, COUNT(o.id) AS orders, SUM(o.total_cents) AS spentFROM customers cJOIN orders o ON o.customer_id = c.idWHERE o.placed_at > now() - INTERVAL '30 days'GROUP BY c.nameORDER BY spent DESCLIMIT 10;

That reads almost as English: which columns, from where, joined how, filtered by what, grouped, sorted, limited. SQL has depth, but this shape covers a large share of everyday work.

Document databases

The other common family stores documents — JSON-like objects — instead of rows. MongoDB and Firestore are the familiar names. Each document can have a different shape, which is flexible early and becomes a liability once six versions of the same record exist in production.

Choosing between them
SituationLean toward
Data with clear relationships — users, orders, invoicesRelational
You'll need to ask questions you haven't thought of yetRelational
Records vary genuinely in shapeDocument
You're unsureRelational — it's the safer default and PostgreSQL stores JSON too

Indexes, and the first slow query

An index is a lookup structure the database maintains so it can find rows without scanning the table. Like the index of a book: without it, finding a topic means reading every page.

index.sql
-- Without this, "find orders for customer 42" reads every order.CREATE INDEX idx_orders_customer ON orders (customer_id);

Indexes aren't free — each one makes writes slightly slower and takes disk. Add them for the queries you actually run, not for every column pre-emptively.

Setting one up sensibly

  1. Sketch your tables on paper firstNouns become tables, relationships become id columns. Ten minutes here saves a migration later.
  2. Add NOT NULL and UNIQUE from the startLoosening a constraint later is easy; tightening one against messy existing data is not.
  3. Use migrations, never manual editsSchema changes as versioned files, applied the same way everywhere.
  4. Set up backups before you have data worth losingA backup you have never restored from is a hypothesis, so test one restore.

Common mistakes

  • Storing money as a floating point number instead of integer cents
  • Storing timestamps without a timezone
  • Skipping constraints because they're inconvenient during early development
  • Never testing a restore, then discovering the backup was empty
  • Adding indexes everywhere as a precaution, which slows every write

Key takeaways

  • A database provides durability, concurrency, integrity, and speed — not merely storage
  • Relational is the safe default; constraints belong in the schema, not only in your code
  • SQL's common shape is readable within a day
  • The first slow query is usually a missing index

Try it yourself

Sketch the tables for your product on paper — every noun a table, every relationship an id column. Then write the constraint for each column: can it be empty, must it be unique, what does it point to? That sketch is a schema.