SUBSCRIBE streams updates from a source, table, view, or materialized view as they occur. Use it to power event-driven applications and replicate data in real-time.
Overview
TheSUBSCRIBE statement is a more general form of SELECT. While SELECT computes a relation at a moment in time, SUBSCRIBE computes how a relation changes over time.
SUBSCRIBE produces a sequence of updates that describe insertions, deletions, and modifications to a relation. This allows you to:
- Power event processors that react to every change
- Replicate the complete history of a relation
- Build real-time streaming applications
Basic Syntax
Simple Example
Subscribe to a materialized view:Output Format
SUBSCRIBE emits rows with metadata columns prepended:
| Column | Type | Description |
|---|---|---|
mz_timestamp | numeric | Materialize’s internal logical timestamp |
mz_diff | bigint | Change in frequency: positive for insertions, negative for deletions |
mz_progressed | boolean | (When PROGRESS option used) Indicates no more updates at earlier timestamps |
| Columns 1-N | Varies | Data columns from the subscribed relation |
Example Output
mz_diff = 1: Row insertedmz_diff = -1: Row deleted- Update = deletion followed by insertion at same timestamp
SUBSCRIBE Options
SNAPSHOT
Controls whether to emit the current state before streaming changes:PROGRESS
Include progress messages to detect periods with no updates:mz_progressed = true and indicate that no updates will arrive for earlier timestamps.
Envelope Options
Envelopes control how changes are formatted in the output.ENVELOPE UPSERT
Reformat output as insert/update/delete operations:mz_state column:
upsert: Insert or update operationdelete: Delete operationkey_violation: Multiple values detected for same key
ENVELOPE DEBEZIUM
Include before and after values for changes:Time Bounds
AS OF
Start subscribing from a specific timestamp:UP TO
Stop subscribing at a specific timestamp:Combined Time Bounds
Client Examples
Python (psycopg2)
Stream updates using cursor-based fetching:Python (psycopg3)
Psycopg3 supports streaming without buffering:Node.js
Stream updates using node-postgres:Java (JDBC)
Stream updates using JDBC:psql with COPY
For interactive sessions, wrapSUBSCRIBE in COPY:
Handling Updates
Map rows to their corresponding updates:Durable Subscriptions
For production systems, configure history retention to resume subscriptions after disconnections:Performance Tips
Use Materialized Views
Subscribe to materialized views instead of indexed views for better performance:Dedicated Clusters
Run subscriptions on dedicated clusters:Batch Fetches
Fetch results in batches with timeouts:Common Patterns
Event Processing
React to every change in a relation:Data Replication
Replicate data to another system:Change Data Capture
Capture and log all changes:Troubleshooting
Driver Buffering
Many PostgreSQL drivers buffer results until a query completes. SinceSUBSCRIBE can run forever, use:
FETCHto retrieve results in batchesAS OFandUP TOto bound the subscription- Driver-specific streaming APIs (e.g., psycopg3’s
stream())
Connection Drops
Handle connection failures gracefully:Next Steps
Query Results
Query point-in-time results with SELECT
Kafka Sinks
Write changes to Kafka topics
SQL Reference
Complete SUBSCRIBE reference
Durable Subscriptions
Configure history retention