# pg_trickle

**pg_trickle** is a PostgreSQL 18 extension that turns ordinary SQL views into
self-maintaining stream tables — no external processes, no sidecars, no
bespoke refresh pipelines. Just `CREATE EXTENSION pg_trickle` and your views
stay fresh.

```sql
-- Declare a stream table — a view that maintains itself
SELECT pgtrickle.create_stream_table(
    name     => 'active_orders',
    query    => 'SELECT * FROM orders WHERE status = ''active''',
    schedule => '30s'
);

-- Insert a row — the stream table updates automatically on the next refresh
INSERT INTO orders (id, status) VALUES (42, 'active');
SELECT count(*) FROM active_orders;  -- 1
```

## The problem with materialized views

PostgreSQL's materialized views are powerful but frustrating.
`REFRESH MATERIALIZED VIEW` re-runs the entire query from scratch, even if
only one row changed in a million-row table. Your choices are: burn CPU on
full recomputation, or accept stale data. Most teams end up building bespoke
refresh pipelines just to keep summary tables current.

## What pg_trickle does differently

pg_trickle captures changes to your source tables and — on each refresh cycle
— derives a *delta query* that processes only the changed rows and merges the
result into the materialized table. One insert into a million-row source table?
pg_trickle touches exactly one row's worth of computation.

The approach is grounded in the [DBSP differential dataflow framework](https://arxiv.org/abs/2203.16684)
(Budiu et al., 2022). Delta queries are derived automatically from your SQL's
operator tree: joins produce the classic bilinear expansion, aggregates
maintain auxiliary counters, and linear operators like filters pass deltas
through unchanged.

## Key capabilities

| Feature | Description |
|---------|-------------|
| **Incremental refresh** | Only changed rows are recomputed — never a full table scan |
| **Cascading DAG** | Stream tables that depend on stream tables propagate deltas downstream automatically |
| **Demand-driven scheduling** | Set a freshness interval on the views your app queries; upstream layers inherit the tightest schedule automatically |
| **Hybrid CDC** | Starts with lightweight row-level triggers; seamlessly transitions to WAL-based logical replication once available |
| **Broad SQL support** | JOINs, GROUP BY, DISTINCT, UNION/INTERSECT/EXCEPT, subqueries, CTEs (including WITH RECURSIVE), window functions, LATERAL, and more |
| **Built-in observability** | Monitoring views, refresh history, NOTIFY-based alerting |
| **CloudNativePG-ready** | Ships as an Image Volume extension image for Kubernetes deployments |

## Demand-driven scheduling

With the default `CALCULATED` schedule mode, you only set an explicit refresh
interval on the stream tables your application actually queries. The system
propagates that cadence upward through the dependency graph: each upstream
stream table inherits the tightest schedule among its downstream dependents.
You declare freshness requirements where they matter — at the consumer — and
the entire pipeline adjusts without manual coordination.

## Hybrid change capture

pg_trickle bootstraps with lightweight row-level triggers — no configuration
needed, works out of the box. Once the first refresh succeeds and
`wal_level = logical` is available, the system automatically transitions to
WAL-based logical replication for lower write-side overhead. The transition
is seamless: `trigger → transitioning → WAL-only`. If anything goes wrong, it
falls back to triggers.

---

## Explore this documentation

- **[Getting Started](GETTING_STARTED.md)** — build a three-layer DAG from scratch in minutes
- **[SQL Reference](SQL_REFERENCE.md)** — every function and option
- **[Architecture](ARCHITECTURE.md)** — how the engine works internally
- **[Configuration](CONFIGURATION.md)** — GUC variables and tuning

---

## Source & releases

Written in Rust using [pgrx](https://github.com/pgcentralfoundation/pgrx).
Targets PostgreSQL 18. Apache 2.0 licensed.

- Repository: [github.com/grove/pg-trickle](https://github.com/grove/pg-trickle)
- Install instructions: [Installation](installation.md)
- Changelog: [Changelog](changelog.md)
- Roadmap: [Roadmap](roadmap.md)
