Delta Updates
Delta updates allow you to perform atomic database operations like increments, decrements, and conditional updates directly at the database level, without needing to read existing values first.
Note: Delta updates are currently a PostgreSQL-only feature. ClickHouse support is not available at this time.
Overview
Traditional database updates require a read-modify-write pattern: fetch the current value, compute the new value, then write it back. This approach has two drawbacks:
Performance overhead - Reading existing values for every update is expensive
Concurrency issues - Race conditions can occur between the read and write
Delta updates solve both problems by expressing the update intent declaratively. The database handles the actual computation atomically.
Requirements
Delta update operations require:
substreams-sink-database-changesRust crate version >= 4.0.0substreams-sink-sqlversion >= 4.12.0PostgreSQL as the target database
Supported Operations
The following delta operations are available on create_row(), update_row(), and upsert_row():
add()
column = COALESCE(column, 0) + value
Atomically increment a numeric column
sub()
column = COALESCE(column, 0) - value
Atomically decrement a numeric column
max()
column = GREATEST(column, value)
Retain the maximum value seen
min()
column = LEAST(column, value)
Retain the minimum value seen
set_if_null()
column = COALESCE(column, value)
Set only if the column is currently NULL
All operations handle NULL values safely using COALESCE, so you don't need to worry about NULL arithmetic.
Usage
Delta operations are chained on the upsert_row() function from the DatabaseChanges API. You can mix regular set() calls with delta operations:
Example: OHLCV Candlestick Data
A practical use case for delta updates is building candlestick (OHLCV) charts from trading data. Each candle needs to track:
Open: First price in the window (set once, never update)
High: Maximum price seen
Low: Minimum price seen
Close: Latest price (always update)
Volume: Cumulative trading volume
This pattern processes each swap event independently. The database handles all the aggregation logic atomically.
For a complete working example, see the Uniswap V4 Candles Demo.
Migration Notes
If you're upgrading from an earlier version of substreams-sink-database-changes, note that the crate package path was reorganized in version 4.0.0. Update your imports:
Further Reading
substreams-sink-database-changes Crate Documentation - API reference for delta update methods
substreams-sink-sql Repository - Sink SQL source code and documentation
Uniswap V4 Candles Demo - Complete working example using delta updates
Last updated
Was this helpful?

