Strategies
append
Inserts new rows without modifying existing data. Optionally uses a cursor (read from the target table’s highest value) to avoid reprocessing the full source on every run.append_cursor_inclusive is true (the default), the lower bound uses >=, which may duplicate the boundary row but avoids missing late-arriving data with the same cursor value. Set to false for an exclusive (>) lower bound if your cursor values are guaranteed unique.
Append without a cursor is also valid. The model simply inserts all rows from the source query on every run.
delete_insert
Deletes rows in the cursor range, then inserts the new delta. Requires eithercursor or unique_key.
delete_insert removes rows where the cursor column falls within the replay window, then inserts the new delta. With a unique_key only, it deletes matching rows by key before inserting.
merge
Upserts rows using a unique key. Matched rows are updated; unmatched rows are inserted.merge always requires unique_key. The cursor controls which upstream rows are scanned; the unique key determines how they’re matched against the target.
Cursors
Cursors define the incremental replay boundary. SQLBuild queriesMAX(cursor) from the target table and MIN/MAX from upstream inputs to compute the replay window automatically.
cursor_inputs
When a model references multiple upstream inputs,cursor_inputs is required to tell SQLBuild which column on each input carries the cursor:
MIN/MAX across the listed inputs and determine the replay window.
Listed inputs bound the window; unlisted inputs do not
Only the inputs you list incursor_inputs bound the replay window. This is an explicit choice, and it has two consequences worth understanding:
- Listed inputs drive the window. Their new data advances the
MAX, which is what tells SQLBuild how far to reprocess and which rows of the target to rewrite. - Unlisted inputs are read in full. SQLBuild does not add a cursor filter to them, and they do not bound the window. This is correct for lookup or dimension tables that have no meaningful cursor column: you do not list them, and SQLBuild reads them whole rather than trying to filter on a column that may not exist.
delete_insert and merge: the target rows that get rewritten are the ones whose cursor falls inside the window derived from the listed inputs. If an unlisted input changes in a way that should affect target rows outside that window, those rows are not rewritten on a normal incremental run. List every input whose new data should drive reprocessing; leave unlisted only the inputs you intend to read in full.
To capture changes that fall outside the normal forward window, see Lookback for late-arriving data and Replay on change for model changes.
Lookback
Lookback extends the start of the replay window backwards to re-process recent data. The cursor is forward-moving, so use lookback to capture late-arriving or backfilled records that land just behind the current position:lookback 3d, the replay window starts 3 days before the normal cursor position, ensuring that any late-arriving data within that window is picked up.
Microbatch execution
For large incremental ranges, microbatch mode splits the replay window into configurable batches. Each batch is processed serially with its own audit cycle: create delta, run delta audits, apply DML, clean up.Batch size
batch_size controls the window size for each batch. For timestamp cursors, use duration strings like 1d, 6h, 1mo. For integer cursors, use an integer value.
Mixed-grain chains
When a downstream microbatch model reads from an upstream model with a coarser time grain, SQLBuild aligns the replay to the coarsest participating grain (the model’s own grain and its cursor-input grains). This happens on every run that resolves cursor bounds from upstream models, not only when something changes. It is independent of thereplay_on_change cascade behavior described below.
Alignment does two things: it floors the replay window edges to the coarsest grain, and it coarsens the batch size to that grain. For example, an hourly model downstream of a daily model processes in day-sized batches, so each batch lines up with a unit of upstream data that actually advances instead of producing empty or boundary-straddling windows:
Replay on change
When a model’s version identity changes (query, config, upstream cascade, or any other change reason),replay_on_change is the explicit, per-model policy for how much data to reprocess. Reprocessing is a policy you set, not an automatic forced rebuild, so a definition change does not silently trigger a full rebuild of large downstream tables. You choose the cost per model:
The bounded duration supports
d (days), h (hours), m (minutes), and s (seconds). For example: bounded-7d, bounded-24h, bounded-30m.

