Overview
The PostgreSQL Realtime Monitor uses logical replication to stream database changes in real-time. This approach captures row-level changes (INSERT, UPDATE, DELETE) with actual data values, enabling the application to react to database modifications as they happen.PostgreSQL Configuration
Logical Replication Setup
The database must be configured with specific settings to enable logical replication (docker-compose.yml:14-18):
Configuration Parameters
wal_level=logical
wal_level=logical
Write-Ahead Log LevelControls the amount of information written to the WAL (Write-Ahead Log):
minimal: Basic crash recovery onlyreplica: Physical replication supportlogical: Full logical decoding support (required for subscriptions)
Setting
wal_level=logical enables row-level change tracking with complete data values.max_wal_senders=10
max_wal_senders=10
Maximum WAL Sender ProcessesLimits the number of concurrent replication connections. Each subscription uses one WAL sender slot.
- Default: 10 (sufficient for most applications)
- Increase if you need more concurrent subscriptions
max_replication_slots=10
max_replication_slots=10
Maximum Replication SlotsReplication slots ensure WAL files are retained until subscribers consume them, preventing data loss during disconnections.
- Each subscription creates a replication slot
- Slots persist across restarts
- Unused slots should be cleaned up to prevent WAL bloat
Publication Setup
Publications define which tables can be subscribed to (init.sql:1):
This publication includes all tables in the database. In production, you may want to create targeted publications for specific tables:
Publication Options
Publications can filter which operations are replicated:postgres.js Subscription
The application uses thepostgres.js library to subscribe to database changes.
Database Connection (db.ts:9-16)
Subscription Setup (src/index.ts:87-124)
The server subscribes to all database changes using the sql.subscribe() method:
Subscription Parameters
Pattern ("*")
The first parameter is a filter pattern:
"*": Subscribe to all operations on all tables"users": Subscribe to changes on theuserstable only"public.*": Subscribe to all tables in thepublicschema
Callback Function
The second parameter is the callback invoked for each change:- row: Object or array containing the row data
- command: The SQL operation type (
insert,update,delete) - relation: Table metadata
- Can be a string (simple table name)
- Can be an object with
schemaandtableproperties
Ready Callback
The third parameter is called when the subscription is established:This callback fires both on initial connection and after reconnection following a disconnection.
Change Processing
Relation Formatting (src/index.ts:91-96)
The relation object is normalized to a consistent string format:
"public.users""inventory.products""orders"(if schema is unspecified)
Row Array Handling (src/index.ts:99-104)
Changes are converted to a consistent array format:
While most changes affect a single row, bulk operations may produce multiple rows in a single callback invocation.
Change Event Structure
INSERT Events
When a row is inserted:UPDATE Events
When a row is updated:UPDATE events contain the new values after the update. Old values are not included by default.
DELETE Events
When a row is deleted:Replica Identity
The REPLICA IDENTITY setting controls what information is included in change events.Setting Replica Identity
Impact on Events
- DEFAULT
- FULL
Primary Key Only
Connection Management
Automatic Reconnection
The postgres.js library automatically handles connection loss and reconnection:- Maintains a replication slot to prevent data loss
- Resumes from the last processed position
- Invokes the ready callback on reconnection
Unsubscribing
Thesql.subscribe() method returns an unsubscribe function:
Performance Considerations
Write Amplification
- Every database write generates WAL entries
- Logical replication adds minimal overhead (~5-10%)
- Impact increases with number of concurrent subscriptions
Network Traffic
- Changes are streamed in near real-time
- High-frequency updates generate proportional network traffic
- Consider batching or throttling for high-volume tables
Memory Usage
- Replication slots retain WAL files until consumed
- Disconnected subscriptions can cause WAL bloat
- Monitor
pg_replication_slotsfor inactive slots
Monitoring Replication Slots
Check active replication slots:Limitations
DDL Changes Not Captured
DDL Changes Not Captured
Logical replication only captures DML operations (INSERT, UPDATE, DELETE). Schema changes (CREATE, ALTER, DROP) are not included in change events.
Truncate Handling
Truncate Handling
TRUNCATE operations may or may not be replicated depending on publication settings. Use DELETE for reliable change tracking.
Sequence Changes
Sequence Changes
Sequence operations (NEXTVAL, SETVAL) are not replicated. Applications should not rely on sequence values being synchronized.
Large Object Support
Large Object Support
PostgreSQL large objects (BLOBs) are not supported by logical replication. Store binary data in BYTEA columns instead.
Best Practices
Set Replica Identity
Use
REPLICA IDENTITY FULL for tables where you need complete DELETE event dataMonitor WAL Growth
Regularly check replication slot lag and clean up inactive slots
Selective Publications
Create targeted publications instead of subscribing to all tables
Handle Reconnections
Implement proper error handling for subscription reconnections
Debugging
Enable Verbose Logging
Add logging to the subscription callback:Check Publication Status
Verify Replication Connection
Related Topics
Architecture Overview
Understand how database subscription fits into the system
WebSocket Implementation
Learn how changes are broadcast to clients