← Mostly Postgres

The Extensible Core

why one database absorbs the work

⚠ warning: slop currently. Work in progress — not final.
In one line
Part 1 said the default is one Postgres. This part says why that default holds: the type system bends to your data instead of forcing your data to bend to it. Extensibility is the mechanism. Everything else in this series is downstream of it.

The reason you rarely need a second database is not luck. It is a founding design choice. Postgres was built so you could add the types, operators, and functions your problem needs, inside the engine, without forking it. That choice is forty years old. It is still paying out.

The system that could not grow

Before Postgres there was Ingres, Michael Stonebraker's first system. Ingres had a fixed set of standard types: integers, floats, text. Good enough for accounting. Not good enough for geography.

A geographic information system needs points, lines, and polygons. It needs to ask whether a point sits inside a region, whether two roads cross. Ingres had no way to add those types. So the academic GIS built on Ingres did not work.

Stonebraker
"as a GIS, the academic version of Ingres was a complete failure"

The failure was not a bug. It was the design. The types were welded in. You took what shipped or you took nothing.

Bond time

The clearest illustration is a customer doing bond financial instruments. Bonds count time in a strange way: every month is thirty days. March 15 minus February 15 is thirty days, full stop. The Gregorian calendar disagrees, and the bond market does not care.

Ingres hardcoded date subtraction to the real calendar. The customer could not change it. So every time he needed bond time, he pulled both dates out of the database into his own code, subtracted them there, and wrote the answer back. A round trip for arithmetic. He measured a 2–3x efficiency hit doing it that way.

He asked the obvious question.

Stonebraker
"Why can't I just overload your definition of subtraction with what I want?"

That question is the whole design brief for Postgres.

The answer: bend the engine, not the data

Postgres said yes. Add your own data types. Add your own operators. Define abstract data types and stored procedures. Make subtraction mean whatever bond time needs it to mean, and make it run inside the engine, fast.

Stonebraker
"Postgres was engineered to have an extendable type system. So you could have whatever data types you wanted and they were very efficient and that was the main gist of Postgres"

Read that last clause again: the main gist of Postgres. Not a feature. The point.

Ingres-shaped
Type not built in → pull data into user code
Round trip for arithmetic, 2–3x slower
GIS impossible; bond time impossible
Postgres-shaped
Type and operator added to the engine
Logic runs where the data lives
GIS and bond time become extensions

The same idea, decades later

The extensibility never went away. It kept absorbing the jobs that, in a different world, each become a separate datastore you run, back up, and reason about.

PostGIS

The GIS that killed academic Ingres is now a Postgres extension. The exact use case that the fixed-type system could not serve is one CREATE EXTENSION away. The wheel came back around.

CREATE EXTENSION postgis;

-- find stops within 500 meters of a point
SELECT name
FROM stops
WHERE ST_DWithin(
  geom,
  ST_SetSRID(ST_MakePoint(-73.985, 40.748), 4326)::geography,
  500
);

pgvector

Embeddings and similarity search, the workload people reach for a dedicated vector database to handle, run as types and operators in the same engine next to the rows they describe.

CREATE EXTENSION vector;

-- nearest neighbors by cosine distance
SELECT id, content
FROM documents
ORDER BY embedding <=> '[0.12, 0.04, 0.91]'
LIMIT 5;

JSONB and full-text search

Documents and search are not bolt-ons either. JSONB gives you a document store with indexes. Full-text search gives you a search engine. Both are built on the same extendable spine that let a customer redefine subtraction. One engine swallows the document database and the search cluster.

What it removes

What extensibility removes is the second database. Geography did not need its own server. Vectors did not. Documents did not. Search did not. Each one would have been a process to run, a copy of your data to keep in sync, a new way for the system to break at 3am.

This is the data-tier reading of the throughline: remove to accelerate. Fewer datastores, fewer failure modes. The choice Stonebraker made because one bond customer was annoyed at calendar math is the same choice that lets your stack stay small today.

Proverb
The type system that bends does not need a neighbor.

Part 1 said: default to one Postgres. This part is the reason that default is honest. The engine grows to fit the problem, so the problem does not need a new engine.

Part 1: The Default · Mostly Postgres · Part 3: Correctness