Choosing a pattern
Two decisions apply to every pattern:
- Streaming or job mode: all examples below are streaming pipelines. For one-time backfills or exports, add
job: true; see Job mode. - Resource size: each section suggests a starting
resource_size. Start small and scale up if the pipeline lags; see the resource size reference for CPU and memory per tier.
Linear pipeline
The simplest shape: one source, one or more chained transforms, one sink.OrderFilled events from an exchange contract and writes clean, typed rows to PostgreSQL:
s for filtered streams; move to m if you backfill a busy contract from earliest.
Related pages:
- SQL transforms for the transform syntax used here
- EVM sources for how
filterspeeds up backfills - PostgreSQL sink for sink options and secret format
Fan-out (one source, multiple sinks)
One source feeds multiple transforms, each writing a different view of the data to a different sink.Default to one pipeline with multiple sinks when you send the same source data to several destinations. Sinks run independently: one failing does not block the others, and each can have its own batching settings. Splitting into one pipeline per destination duplicates source ingestion and wastes resources. Split only when the destinations need different resource sizes or genuinely independent lifecycles.
m; multiple sinks mean more concurrent work than a linear pipeline.
Related pages:
- Multiple sinks for how sinks behave independently
- ClickHouse sink and webhook sink for sink-specific options
Fan-in (multiple inputs, one sink)
Multiple event types are decoded from the same source, normalized to a common schema, and combined withUNION ALL into a single sink.
UNION ALL requires:
l; decoding plus many transforms is the heaviest shape in this guide.
Multi-chain fan-in
The same shape works with multiple sources instead of multiple event types: combine chains into one output withUNION ALL.
m for two chains and l as you add more. If the chains do not need to land in the same table, prefer the templated deployment below.
Multi-chain templated deployment
When you need the same pipeline logic across multiple chains, deploy one pipeline file per chain rather than a single multi-source pipeline.- Independent lifecycle: deploy, pause, or delete one chain without touching the others
- Independent checkpointing: one chain failing or lagging doesn’t block the others
- Clearer monitoring: each chain has its own pipeline status and logs
ethereum-transfers.yaml
Templated vs. multi-source
Resource size:
m per chain. Because each chain runs in its own pipeline, you can also size each one independently: a busy chain can run l while a quiet one runs s.
Dynamic table architecture
Dynamic tables give a pipeline runtime-updatable lookup data, the Turbo answer to “no joins in streaming SQL”. Adynamic_table transform is backed by a table (typically PostgreSQL) that you can update at any time without restarting the pipeline, and SQL transforms query it with the dynamic_table_check() function.
Pattern: dynamic allowlist or blocklist
WHERE ... IN list.
This example only keeps transfers that touch a tracked wallet:
Pattern: lookup enrichment
sql: query; see the factory pattern example.
Choosing a backend
Use
Postgres for production: it persists across restarts and can be updated externally.
Sizing considerations
- Dynamic tables add memory overhead proportional to table size, so for large lookup tables (over ~100K rows) use the
Postgresbackend. - Lookups are batched and indexed, but cost still scales with table size, so keep tables as small as your use case allows.
- Resource size:
sis usually enough for allowlist filtering; size for your transform complexity, not for the dynamic table itself.
dynamic_table_check reference.
PostgreSQL aggregate sink pattern
Thepostgres_aggregate sink maintains real-time running aggregations (balances, counters, totals) using a two-table pattern: a landing table receives raw events, and a database trigger incrementally updates an aggregation table.
sum, count, avg, min, max. Not every function supports every operation type: sum and avg cannot handle updates, and min/max are insert-only. See supported aggregation functions before choosing.
This example tracks every token and holder on Ethereum Mainnet, which is a high write volume for a Postgres database. For production, add a
WHERE clause to track specific tokens, or size your database accordingly.m. Throughput is usually bounded by the Postgres database rather than the pipeline, so scale the database before scaling the pipeline.
For landing-table deduplication, trigger internals, and update/delete semantics, see the PostgreSQL aggregation sink reference.
Next steps
- Copy-paste starting points for all of these patterns (and more) live in the pipeline cookbook.
- Full YAML field reference: pipeline configuration.
- Deploy and monitor with the CLI reference.