C.W.K.
Stream
Lesson 02 of 06 · published

Backfills, Reruns, and Time-Travel Reads

~11 min · backfill, production, idempotency

Level 0Curious Reader
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Backfills are the thing your future self will thank you for designing

The day you discover a bug that's been silently corrupting a metric for three weeks, you have two options: fix the code going forward, or fix the code and rerun the corrected pipeline for the past three weeks. The second option is a backfill, and it only works if your pipeline was designed for it.

What makes a pipeline backfillable

  • Parameterized by window. The pipeline takes a logical date / window as input — not NOW().
  • Idempotent writes. Rerunning for a window replaces, not appends.
  • No hidden state. No "only run for new rows since last run" without an explicit watermark you can override.
  • Source data is reachable. The upstream API or warehouse can serve the historical window — check this before the bug, not after.

Time-travel reads

Modern lakehouse formats (Iceberg, Delta Lake) support time-travel reads — "give me this table as it was on 2026-04-01." This is a separate idea from backfilling — backfilling rewrites history, time-travel reads from the past as it was. Together they let you answer "what would yesterday's report have shown if the bug had been fixed two weeks ago?" — a question that's invaluable when explaining changes to stakeholders.

Code

A backfill loop that respects rate limits and idempotency·python
from datetime import date, timedelta
import time
import logging

log = logging.getLogger('backfill')

def backfill(start: date, end: date, *, sleep_seconds: float = 1.0) -> None:
    '''Re-run the pipeline for each day in [start, end), oldest first.
    Each day is a partition; rerunning is safe because the load is partition-replace.
    '''
    cur = start
    while cur < end:
        log.info('backfill day=%s', cur)
        run_pipeline(window=cur.isoformat())   # the same entry point as production
        cur += timedelta(days=1)
        time.sleep(sleep_seconds)              # be kind to upstream

# Example: re-process the last 21 days because we just fixed a bug
backfill(date(2026, 4, 9), date(2026, 4, 30))

External links

Exercise

Pick a scheduled pipeline you own (or a hypothetical one). Audit it for backfillability: (1) does it take a window parameter, (2) is the load idempotent, (3) is the upstream source historical, (4) does it depend on any "current state" that's hard to reproduce? Score the pipeline 0–4. Anything below 4 is a future-tax waiting to come due.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.