Infrastructure · Substrate Atlas

PostgreSQLExtensions

Audience: Anyone building data harnesses on Postgres — quant researchers, experimental scientists, knowledge engineers, platform builders.

Goal: Understand what each extension does in one line — and which problem it solves in your domain.

You do not need a separate vector DB, graph DB, and time-series DB if Postgres + extensions fit your scale. This guide helps you choose.

13 + built-in FTS
vector · age · pg_trgm
one Postgres hub

Section 00

How to read this doc

SectionPurpose
TLDR tablePick extensions in 60 seconds
Per-extensionDefinition → when to use → examples by field
Head-to-headAGE vs Neo4j, pgvector vs Pinecone, and more
Decision matrix"I need X" → extension Y
Harness patternsFour extension stacks — read left to right
Install orderSafe rollout on research or prod server

Built-in (no extension): PostgreSQL already includes full-text search (to_tsvector, tsquery), JSONB, Arrays and window functions. Many projects never need more than that.

Section 01

TLDR

ExtensionTLDR (one line)Typical domains
vectorStore vectors; find nearest neighbors by cosine/L2 distanceML embeddings, semantic search, compound similarity
ageProperty graphs + Cypher inside PostgresNetworks, supply chains, citation graphs, knowledge graphs
pg_trgmFuzzy text match (typos, near-duplicates)Entity names, tickers, chemical synonyms, log grep
btree_ginEfficient GIN indexes on JSONB and composite keysMetadata filters, experiment parameters in JSON
pg_stat_statementsProfile SQL: which queries cost the most timeProduction, heavy notebook-driven workloads
pg_cronSchedule SQL inside the databaseNightly ETL, rollups, model refresh, cleanup
ltreeTree paths as a native type (a.b.c.d)Taxonomies, BOMs, org charts, folder hierarchies
citextCase-insensitive text columnsSymbols, gene names, user handles
timescaledbTime-series hypertables, retention, compressionMarket ticks, sensor streams, lab instrument logs
rum / pg_bm25Better-ranked full-text search than default ts_rankLiterature search, document corpora
hypopgTest hypothetical indexes (EXPLAIN only)Index tuning before migration
pg_repackOnline table rewrite to remove bloatLong-running append/update tables
postgisGeometry and spatial predicates (points, polygons)GIS, microscopy coordinates, field sites

Section 02

The harness-building idea

A data harness is a stable layer between raw inputs (files, APIs, instruments) and your analysis (Python, R, notebooks, dashboards). Postgres is often enough as the hub.

Data flow · substrate layers
flowchart TB
  SRC["Instruments / APIs / Files"]
  ETL["ETL / ingest"]
  subgraph PG["PostgreSQL — relational core + extensions"]
    direction TB
    V["vector → similarity search"]
    AGE["age → graph traversal"]
    TS["timescaledb → time buckets"]
    GIS["postgis → spatial filters"]
  end
  NB["Notebooks"]
  DASH["Dashboards"]
  BATCH["Batch jobs"]
  SRC --> ETL --> PG
  PG --> NB
  PG --> DASH
  PG --> BATCH
          

Why extensions instead of many databases? One backup, one connection model, joins between embeddings and metadata, transactional consistency. Trade-off: you must know which extension fits which shape of data.

Section 03

Tier 1 — high leverage

vector (pgvector)

TLDR: Adds a vector column type and distance operators for approximate nearest neighbor (ANN) search over embeddings.

When to use

  • Fixed-length numeric vectors (embeddings, spectra fingerprints, latent states).
  • “Find the k most similar rows” is a core query.
  • Vectors in the same table as labels, timestamps, and JSON metadata.

When not to use

Billion-scale ANN with strict sub-10ms SLA — you may later shard or add a dedicated vector service. For thousands to low millions of rows, pgvector is often sufficient.

DomainExample use
Quant / MLEmbed research notes or news headlines; retrieve context for factor models
PhysicsSimilarity over reduced simulation state vectors; cluster regimes
ChemistryMolecular fingerprints (ECFP, etc.) stored as vectors; nearest analogs
Knowledge systemsSemantic search over archival text chunks (embedding + content in one row)
CREATE EXTENSION vector;

CREATE TABLE compounds (
  id serial PRIMARY KEY,
  smiles text,
  fingerprint vector(2048)
);

SELECT id, smiles, fingerprint <=> $1 AS distance
FROM compounds
ORDER BY distance
LIMIT 20;

age (Apache AGE)

TLDR: Adds a labeled property graph and openCypher inside PostgreSQL — graph pattern matching without a separate Neo4j server.

When to use

  • Relationships are as important as entities (who traded with whom, what cites what, what reacts with what).
  • Multi-hop queries: “friends of friends”, “supply chain depth 3”, “path from concept A to B”.
  • Graph + SQL joins in one transaction.

When not to use

Pure trees (use ltree or adjacency list). Massive graph analytics at internet scale with dedicated ops team — consider a dedicated graph engine.

DomainExample use
Quant FinanceCounterparty network, correlated exposure paths, instrument dependency graph
PhysicsCitation / collaboration networks; coupling between subsystems in a model catalog
ChemistryReaction networks: (Molecule)-[:REACTS_IN]->(Reaction)-[:PRODUCES]->(Molecule)
Knowledge systems(Episode)-[:ABOUT]->(Person), (Episode)-[:REFERENCES]->(Document)
Reaction graph
graph LR
  M1(("Molecule A"))
  R(("Reaction"))
  M2(("Molecule B"))
  M1 -->|REACTS_IN| R -->|PRODUCES| M2
            
CREATE EXTENSION age;
LOAD 'age';

SELECT * FROM cypher('science_graph', $$
  MATCH (a:Molecule {name: 'benzene'})-[:REACTS_IN*1..3]-(b:Molecule)
  RETURN DISTINCT b.name
$$) AS (name agtype);

Note: AGE implements a subset of openCypher. Complex graph algorithms (PageRank at huge scale) may still belong in batch frameworks — but traversal and pattern match often belong here.

pg_trgm

TLDR: Trigram similarity — match strings that are almost equal (typos, formatting differences).

When to use

  • User-facing search over names, symbols, or labels with inconsistent spelling.
  • Deduplication: “are these two instrument IDs the same?”
  • Joining messy external data to a clean registry.
DomainExample use
Quant FinanceBRK.A, BRK-A, Berkshire in a corporate-action lookup
PhysicsFuzzy match on experiment IDs or collaborator names in lab notebooks
ChemistrySynonym resolution: acetone vs. propan-2-one in imported catalogs
Knowledge SystemsTag search when users type redroom vs. red-room type
CREATE EXTENSION pg_trgm;

SELECT name, similarity(name, 'Hilbert space') AS sim
FROM papers
WHERE name % 'Hilbert space'
ORDER BY sim DESC
LIMIT 10;

Pitfall: Short tokens (nic, ion) can false-positive inside longer words — use word boundaries or minimum similarity thresholds in production.

btree_gin

TLDR: Enables GIN index patterns that combine equality and containment — especially powerful for JSONB keys and multi-column GIN.

When to use

  • Heavy filtering on metadata->>'parameter' or nested JSON experiment configs.
  • You run WHERE properties @> '{"solvent": "water"}' at scale.
DomainExample use
QuantFilter backtest runs by strategy params in JSONB
PhysicsQuery simulations by lattice size, boundary condition in metadata
ChemistryFilter reactions by catalyst family in JSON protocol blob
KnowledgeFilter records by source, person_id, scores in JSON
CREATE EXTENSION btree_gin;
CREATE INDEX ON runs USING gin ((config->'solver'));

Section 04

Tier 2 — operations, time, and structure

pg_stat_statements

TLDR: Records aggregate stats per normalized SQL statement — the standard way to find slow queries.

When to use: Any database that matters — notebook-driven chaos eventually becomes someone’s 3am incident.

CREATE EXTENSION pg_stat_statements;
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 15;

pg_cron

TLDR: Cron-style job scheduler that runs SQL inside Postgres.

When to use

  • Nightly aggregation, partition maintenance, embedding refresh.
  • Schedules versioned next to schema, not scattered on host crontab.
DomainExample
QuantRoll up minute bars to daily at market close
PhysicsArchive completed simulation batches
ChemistryRefresh compound property cache from external API
CREATE EXTENSION pg_cron;
SELECT cron.schedule('nightly-rollup', '0 2 * * *', $$CALL rollup_daily()$$);

Security: Restrict who can create jobs; treat like superuser capability.

ltree

TLDR: Stores materialized paths in a tree (root.child.grandchild) with fast ancestor/descendant operators.

When to use

  • Strict hierarchies: taxonomy, file paths, bill of materials.
  • Simpler than a full graph when edges are only parent→child.
DomainExample
Quantasset.equity.us.tech.AAPL classification path
Physicsproject.detector.run42.config.v3
Chemistryorg.chemclasses.alkanes.C12
Knowledgecollection.person.week.episode container paths
CREATE EXTENSION ltree;
SELECT * FROM nodes WHERE path <@ 'project.detector.run42';

vs AGE: ltree = trees; AGE = arbitrary graphs (cycles, many edge types).

citext

TLDR: Case-insensitive text type — comparisons ignore case without LOWER() everywhere.

When to use: Symbols, gene names, handles where case drift causes duplicate rows.

timescaledb

TLDR: First-class time-series — automatic partitioning by time, retention policies, compression.

When to use

  • High ingest rate of (timestamp, value, tags) — market data, sensors, lab instruments.
  • Queries are mostly “range over time” + aggregates.
DomainExample
QuantTick or bar storage; VWAP windows
PhysicsDAQ channel streams from an experiment
ChemistryChromatography or spectrometer time traces
CREATE EXTENSION timescaledb;
SELECT create_hypertable('sensor_readings', 'time');

Section 05

Tier 3 — search quality, tuning, maintenance, space

Built-in full-text search (tsvector / tsquery)

TLDR: Keyword search with tokenization and ranking — no extension required.

When to use: Document bodies, abstracts, log messages — exact and stemmed word match, not embedding similarity.

DomainExample
QuantSearch research PDF extract for “carry trade”
PhysicsGrep paper corpus for “renormalization”
ChemistryFind procedures mentioning “Grignard”
CREATE INDEX ON papers USING gin (to_tsvector('english', abstract));
SELECT title FROM papers
WHERE to_tsvector('english', abstract) @@ plainto_tsquery('english', 'topological insulator');

rum / pg_bm25

TLDR: Full-text indexes with BM25-style relevance — often better ranking than ts_rank_cd.

When to use: Large corpora where keyword relevance quality matters (literature, regulations, patents).

hypopg

TLDR: Hypothetical indexes — planner considers them in EXPLAIN without building them.

When to use: Before adding heavy indexes on production tables; compare plan cost estimates.

pg_repack

TLDR: Rebuilds tables online to reclaim space from update/delete bloat.

When to use: Append-heavy or churn-heavy tables (event logs, archival stores) when VACUUM is not enough.

postgis

TLDR: Spatial types and predicates — distance, containment, intersections on Earth or projected CRS.

When to use: Field sampling sites, microscopy stage coordinates, geographic portfolios.

DomainExample
QuantBranch/store locations for regional risk
Physics / Earth scienceSensor geolocation; field campaign sites
ChemistryLess common — unless environmental sampling maps
CREATE EXTENSION postgis;
SELECT id FROM sites
WHERE ST_DWithin(geom, ST_MakePoint(-73.98, 40.75)::geography, 5000);

Section 06

Head-to-head comparisons

When does a Postgres extension beat a dedicated service — and when does the dedicated tool still win?

Graph

Apache AGE vs Neo4j

DimensionAGE + PostgresNeo4j
ArchitectureGraph inside your existing DBSeparate graph server + sync
SQL joinsNative — episodes + metadata in one queryRequires ETL or app-layer merge
CypheropenCypher subsetFull Cypher + graph algos
OpsOne backup, one connection poolTwo systems to monitor
ScaleResearch / platform scale (millions of edges)Internet-scale graph analytics
Pick AGE whenGraph traversal + relational truth in one transaction; no Neo4j ops budget
Pick Neo4j whenDedicated graph team, heavy GDS algorithms, strict graph-only SLA

Vectors

pgvector vs Pinecone / Qdrant

DimensionpgvectorDedicated vector DB
Data modelVectors + JSON metadata in same rowVectors often separate from source of truth
FilteringSQL + GIN on metadata alongside ANNMetadata filters vary by vendor
Latency at huge scaleGood to ~low millions; shard laterSub-10ms at billions with HNSW tiers
CostPostgres you already runExtra SaaS or cluster
Pick pgvector whenEmbeddings live with archival rows; hybrid semantic + SQL filters
Pick dedicated whenGlobal ANN at billions, strict latency SLA, separate vector team

Time series

TimescaleDB vs InfluxDB

DimensionTimescaleDBInfluxDB
Query languageSQL — joins with relational dataInfluxQL / Flux
HypertablesAuto partition + retention in PostgresBuilt for metrics from day one
EcosystemSame ORMs, same backups as PostgresSeparate ingest + tooling
Pick Timescale whenTicks/bars/sensors must join to reference tables in SQL
Pick Influx whenPure metrics pipeline, no relational joins needed

Search

Postgres FTS vs Elasticsearch

DimensionPostgres FTS (+ rum)Elasticsearch
SetupBuilt-in; rum/pg_bm25 for better rankSeparate cluster + sync pipeline
StrengthKeyword + metadata in one DBFull-text at massive doc scale, analyzers
Pick Postgres whenCorpus fits in Postgres; hybrid keyword + vector + graph
Pick Elasticsearch whenHuge document index, complex analyzers, search-only team

Spatial

PostGIS vs MongoDB Geo

DimensionPostGISMongoDB GeoJSON
Data modelGeometry types + SQL joins to relational rowsGeoJSON documents in a document store
StandardsOGC predicates, CRS, topology, raster2dsphere indexes; simpler geo queries
StrengthField sites + lab metadata + vectors in one queryFast geo-in-document apps without SQL
Pick PostGIS whenSpatial filters must join experiments, portfolios, or samples in SQL
Pick Mongo whenDocument-first app; geo is a filter on JSON blobs only

Section 07

Decision matrix

You need…Start hereAlso consider
Similarity on embeddingsvector—
“Related items” by meaning + filtersvector + btree_gin on metadata—
Multi-hop relationshipsageltree if strict tree only
Typo-tolerant name/symbol searchpg_trgmcitext for equality
Time-range aggregates at scaletimescaledbnative partitioning
Keyword search in documentsBuilt-in FTSrum if ranking weak
Map / distance queriespostgis—
Slow query diagnosispg_stat_statements—
Scheduled SQL maintenancepg_cronexternal orchestrator
Index tuning without riskhypopg—

Section 08

Harness patterns

Four ready-made extension stacks. Each row is one layer in the harness — read left to right, then the hub line shows what you get.

A → B → C extension layers in order → hub combined outcome / API surface animated arrows data flows left to right
A

Semantic lab notebook

Scientists write notes; you need meaning search, fuzzy IDs, and JSON experiment filters — without three databases.

vectorembed note paragraphs
→
pg_trgmfuzzy sample IDs
→
FTSkeyword fallback
→
JSONB+ginexperiment params
→ unified lab search API
B

Market + exposure graph

Time-series bars, counterparty relationships, and news context — one harness for quant risk.

timescaledbbars & ticks
→
agecounterparty graph
→
vectornews embeddings
→
pg_stat_statementstune hot paths
→ exposure + context dashboard
C

Chemical intelligence

Fingerprint similarity, reaction networks, and site sampling — chemistry R&D in one Postgres hub.

vectorfingerprint similarity
→
agereaction network
→
postgissite sampling
→
pg_trgmsynonym matching
→ compound discovery pipeline
D

Episodic knowledge archive

Long-horizon agent memory: semantic recall, people/doc graph, fast API reads — no Postgres + Neo4j + vector SaaS.

vectorsemantic recall
→
ageepisode graph
→
pg_trgmfuzzy tags
→
edges tablematerialized + gin
→ relational truth + materialized links + optional Cypher
All patterns · one database hub
flowchart TB
  subgraph PA["A · Lab notebook"]
    direction LR
    v1[vector] --> h1[(search)]
    t1[trgm] --> h1
  end
  subgraph PB["B · Market graph"]
    direction LR
    ts2[timescale] --> h2[(risk)]
    a2[age] --> h2
  end
  subgraph PC["C · Chemistry"]
    direction LR
    v3[vector] --> h3[(discovery)]
    g3[postgis] --> h3
  end
  subgraph PD["D · Knowledge"]
    direction LR
    v4[vector] --> h4[(memory)]
    a4[age] --> h4
  end
  PG[(PostgreSQL hub)]
  PA --> PG
  PB --> PG
  PC --> PG
  PD --> PG
          

Section 09

Suggested install order

Any serious Postgres harness — core first, domain-specific when needed.

-- Core analytics
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS btree_gin;

-- Observability
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- Domain-specific (add when needed)
CREATE EXTENSION IF NOT EXISTS age;          -- graphs
CREATE EXTENSION IF NOT EXISTS timescaledb;  -- time series
CREATE EXTENSION IF NOT EXISTS postgis;      -- spatial
CREATE EXTENSION IF NOT EXISTS pg_cron;      -- schedules (policy!)

Match extension packages to your Postgres major version (e.g. postgresql-16-pgvector).

Section 10

What extensions do not replace

NeedExtension helps but…
Training neural netsStore vectors; train in Python/Julia
Heavy graph ML (GNN training)Export subgraphs to PyG/DGL
Sub-millisecond global ANN at billionsDedicated vector tier may be needed
Full document OCRStore text after extraction
Real-time stream processing at Kafka scaleIngest via stream processor; Postgres as sink

Section 11

Security checklist

  • Treat pg_cron and age as privileged capabilities on shared servers.
  • Do not expose arbitrary Cypher/SQL endpoints to untrusted users without allowlists.
  • Extension install often requires superuser — document who can change shared_preload_libraries.
  • Fuzzy matchers (pg_trgm) can leak existence of similar strings — tune thresholds on sensitive data.

Further reading

Section 12

Changelog

DateChange
2026-06-08Initial release — cross-domain educational guide
2026-06-08Head-to-head comparisons, mobile layout, animated diagrams