How Postgres extensions replace entire categories of specialized databases — without leaving ACID behind.
Module 15 — The Extensions Ecosystem: pg_cron, TimescaleDB, Citus, and pgvector
What this module covers: PostgreSQL's extension system is its most underappreciated feature. Extensions add capabilities that match or exceed dedicated NoSQL databases — without leaving the ACID guarantees, SQL interface, and operational tooling you already have. This module covers the four extensions that most frequently eliminate the need for a separate database:
pg_cronfor background job scheduling, TimescaleDB for time-series at scale, Citus for horizontal sharding, andpgvectorfor AI/embedding workloads.
Why Extensions Matter
In Module 11, we compared Postgres to MongoDB, Cassandra, and ClickHouse. Those comparisons assumed vanilla Postgres. With extensions, the picture changes:
- Need time-series with columnar compression? → TimescaleDB makes Postgres competitive with InfluxDB and ClickHouse
- Need horizontal write scaling? → Citus distributes Postgres across many nodes
- Need vector similarity search for AI? →
pgvectormakes Postgres competitive with Pinecone and Weaviate - Need background job scheduling? →
pg_cronreplaces external cron + application-layer job tables
Each extension adds specialized capabilities while keeping the full Postgres stack: MVCC, WAL, ACID, SQL, pg_stat_*, your existing monitoring, your existing connection pooler, your existing backup tooling.
pg_cron: Background Job Scheduling Inside Postgres
pg_cron runs SQL or stored procedures on a cron schedule, directly inside the database process. No external scheduler, no separate worker service, no application-layer job table.
Installation and Setup
Scheduling Jobs
Managing Jobs
When pg_cron Is the Right Tool
pg_cron is ideal for:
- Database maintenance tasks (ANALYZE, VACUUM, partition creation)
- Data retention cleanup (delete rows older than N days)
- Periodic aggregation into summary tables
- Refreshing materialized views on a schedule
It is not suitable for:
- Long-running jobs that need external resources (API calls, file I/O)
- Jobs that need distributed coordination across multiple Postgres instances
- Jobs with complex dependency graphs (use Airflow, Prefect, or similar)
TimescaleDB: Time-Series at Postgres Scale
TimescaleDB is an open-source extension that adds automatic time-based partitioning (hypertables), columnar compression, and time-series-specific query functions on top of Postgres.
Hypertables
A hypertable is a Postgres table with automatic time-based partitioning managed by TimescaleDB. Data is partitioned into "chunks" automatically — no manual CREATE TABLE partition ... required.
The hypertable looks and behaves like a regular Postgres table. All standard SQL works. TimescaleDB handles partitioning transparently.
Columnar Compression
TimescaleDB's native columnar compression is the feature that makes it genuinely competitive with InfluxDB and ClickHouse for time-series workloads.
Typical compression ratios for time-series data: 10–40x. A 100GB raw metrics table becomes 3–10GB compressed. Compressed chunks are read using a columnar scan — only the requested columns are decompressed, dramatically reducing I/O for aggregation queries.
Continuous Aggregates
Continuous aggregates are materialized views that update automatically as new data arrives:
Data Retention
TimescaleDB vs Plain Postgres Partitioning
| Plain Postgres Partitioning | TimescaleDB | |
|---|---|---|
| Partition creation | Manual or pg_partman | Automatic |
| Columnar compression | No | Yes (10–40x) |
| Continuous aggregates | Manual with triggers | Native |
| Retention policies | Manual pg_cron job | Native |
| SQL compatibility | Full | Full |
| Extension required | No | Yes |
TimescaleDB is the right choice when: you have high-volume time-series data (metrics, events, IoT) that needs compression and fast aggregate queries, and you want to stay on Postgres rather than migrating to InfluxDB or ClickHouse.
Citus: Horizontal Sharding for Postgres
Citus distributes a Postgres database across multiple nodes — sharding both data and query execution. It is built by Microsoft and available as an open-source extension or managed service (Azure Cosmos DB for PostgreSQL).
The Citus Architecture
Distribution Key Selection
The distribution key is the most critical decision. Choose it so:
- Frequently joined tables are colocated — if
transactionsandblocksare joined frequently, distribute both by a compatible key - Hot queries filter on it —
WHERE sender = '0xabc...'goes to one shard, not all shards - Data is evenly distributed — high-cardinality columns like UUIDs or blockchain addresses
Reference Tables
Some tables are small and frequently joined — distribute them to all workers:
When Citus Is the Right Answer
Citus is appropriate when:
- Write throughput exceeds what a single Postgres instance handles (~50,000+ TPS)
- Data volume exceeds what a single server stores efficiently (10+ TB)
- Most queries filter on the distribution key — if queries frequently scan all shards, sharding adds overhead without benefit
For most applications below these thresholds, a single Postgres primary with read replicas is simpler and sufficient.
pgvector: Vector Embeddings for AI Workloads
pgvector adds a vector data type and vector similarity search indexes to Postgres. It is the extension that makes Postgres competitive with dedicated vector databases like Pinecone, Weaviate, and Chroma for AI/RAG (Retrieval-Augmented Generation) workloads.
What Vector Search Is
An embedding is a fixed-size array of floating-point numbers that represents the semantic meaning of text, an image, or any other content. Embeddings with similar meaning have small vector distances. Searching for the most similar embeddings is the core operation in:
- RAG (Retrieval-Augmented Generation): find documents semantically similar to a query, feed them to an LLM as context
- Semantic search: return results by meaning, not keyword matching
- Recommendation systems: find items similar to what a user engaged with
- Duplicate detection: find near-duplicate content by vector proximity
Installation and Schema
Inserting Embeddings
Vector Similarity Search: Exact vs Approximate
Exact search (no index — scans all vectors):
Operators:
<->— L2 (Euclidean) distance<#>— negative inner product (for dot product similarity)<=>— cosine distance (most common for text embeddings)
Exact search is O(N) — every vector is compared. For up to ~100K vectors, this is fast enough. Above that, you need an approximate nearest-neighbor (ANN) index.
IVFFlat Index
IVFFlat (Inverted File Flat) divides vectors into lists clusters. A query searches only the nearest N clusters instead of all vectors.
Recall vs speed trade-off:
probes = 1: fastest, lowest recall (~70% of exact results)probes = 10: balanced (~90% recall)probes = lists: exact search (same as no index)
Build IVFFlat only after the table has data — the index quality depends on the data distribution at build time. Rebuild if data distribution changes significantly.
HNSW Index (Recommended)
HNSW (Hierarchical Navigable Small World) builds a graph-based index with better recall/speed trade-offs than IVFFlat for most workloads.
HNSW vs IVFFlat:
| IVFFlat | HNSW | |
|---|---|---|
| Build time | Fast | Slower (especially for large datasets) |
| Memory | Lower | Higher (graph stored in memory) |
| Recall at same speed | Lower | Higher |
| Incremental inserts | Requires rebuild for best quality | Good — inserts update the graph |
| Best for | >1M vectors, memory-constrained | Most workloads, especially with inserts |
Hybrid Search: Vector + SQL Filters
The real power of pgvector in Postgres: combine semantic vector search with SQL predicates in one query:
A dedicated vector database requires an additional filter step after the ANN search — often requiring you to fetch more candidates than needed and filter in the application. Postgres does this in a single query with the planner's cost model deciding the optimal execution order.
pgvector vs Dedicated Vector Databases
| pgvector | Pinecone / Weaviate | |
|---|---|---|
| ACID transactions | Yes | No |
| SQL filters in same query | Native | Post-processing |
| Operational complexity | Same as Postgres | New system to operate |
| Metadata storage | JSONB + columns | Separate metadata store |
| Scale | ~100M vectors (1536-dim, 128GB RAM) | Unlimited (distributed) |
| Cost | Postgres hosting cost | Per-vector pricing |
For most RAG and semantic search applications below 100M vectors: pgvector in Postgres eliminates the need for a dedicated vector database entirely. Your embeddings, metadata, and business data live in one system with consistent transactions.
Summary
| Extension | Replaces | When to Use |
|---|---|---|
pg_cron | External cron + job tables | DB maintenance, data cleanup, periodic aggregation |
| TimescaleDB | InfluxDB, ClickHouse (time-series) | High-volume time-series, IoT metrics, automated compression |
| Citus | Manual sharding, Cassandra (write scale) | >50K TPS write throughput or >10TB single-table datasets |
pgvector | Pinecone, Weaviate, Chroma | RAG, semantic search, recommendation systems, <100M vectors |
The principle: before adding a new database to your infrastructure, check if a Postgres extension solves the problem. The operational cost of one well-understood Postgres cluster is almost always lower than operating two specialized systems.
A software engineer needs to schedule a daily job that fetches data from an external REST API, processes it, and then inserts it into a PostgreSQL database. Considering the architectural design and limitations of pg_cron, which of the following statements is most accurate regarding its suitability for this task?
A team is building a RAG system with pgvector for a dataset of 50 million document embeddings (1536-dimensional). They anticipate frequent inserts and updates to the document collection, and require high recall for their semantic search queries, even at the cost of slightly slower query times. Which pgvector indexing strategy is most appropriate for this scenario?
A data engineering team is migrating a high-volume IoT sensor data pipeline to TimescaleDB. They've configured hypertables with 7-day chunk intervals and enabled columnar compression for chunks older than 30 days. They observe significant storage savings and are now optimizing dashboard queries that aggregate AVG(temperature) and MAX(humidity) over various time ranges. What is the primary performance benefit of TimescaleDB's columnar compression for these aggregation queries?
Test your knowledge with more question sets
Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.
Sign in & RegisterDiscussion
0Join the discussion