Every real data pipeline is eventually run twice. A job times out and is retried, a deployment restarts a worker mid-batch, an analyst asks for a backfill of last quarter. If a re-run produces duplicates or corrupts the target, every operational hiccup becomes a data-quality incident. Designing for idempotency removes that fear.

Key takeaways

  • An idempotent pipeline gives the same result whether it runs once or several times.
  • Extract incrementally using a watermark, with a safety overlap, and load with a keyed merge.
  • Keep transformations deterministic and separate raw, cleaned and curated layers.
  • Use a durable orchestrator so retries resume where they stopped.

Incremental extraction with a watermark

Reading the whole source each day does not scale. Instead, record a watermark, such as the latest modification timestamp or sequence number successfully processed, and next time fetch only records changed after it. Store the watermark in the target system, so it moves only when the data has actually landed. Two cautions: clocks and commit order can make a late-arriving row carry an older timestamp than the watermark, so re-read a small overlapping window; and deletes are invisible to a "changed since" query, so decide how you will detect them, such as soft-delete flags, change feeds or periodic full comparisons.

Load with a keyed merge

Append-only loads create duplicates when re-run. Instead, load into a staging table and merge into the target on a stable business key: update rows that exist, insert those that do not. Because the key decides identity, running the same batch twice leaves the target unchanged. When a source does not offer a natural key, define one deliberately, for example from a combination of fields, and document it.

Keep transformations deterministic

The same input should always produce the same output. Avoid depending on the current time, random values or the order rows arrive, unless you pass them in explicitly as parameters. Version the transformation logic and record which version produced which data. Validate data with typed models so malformed records fail loudly at the edge.

Use layers

A common structure, often called the medallion pattern, keeps data in stages. A raw layer stores records as received, untouched, so you can always reprocess. A cleaned layer applies typing, deduplication and standardization. A curated layer shapes data for reporting and analytics. Each layer can be rebuilt from the one before it, which makes fixes and backfills straightforward.

Orchestrate with durability

Schedulers that simply run scripts leave you to handle failure by hand. Durable workflow engines, such as Temporal, persist the progress of each workflow, so when a step fails or a worker restarts, execution resumes at that step with its retry policy. This suits pipelines made of listing and per-item processing steps: first discover what is available, then process each item in parallel, with retries and timeouts managed by the engine. Keep the individual steps idempotent anyway; durable execution and idempotency work together.

Check quality as you go

  • Row counts and control totals between stages.
  • Constraint checks on keys, required fields and allowed values.
  • Freshness checks so you notice when data stops arriving.
  • Reconciliation against the source for critical measures.

Surface failures to the people who can act on them, with enough context to resolve them.

Handle secrets and environments

Keep credentials in a managed secret store and inject them at run time. Run the same pipeline code across development, test and production, with configuration, not code, controlling the differences.

Backfills become boring

When pipelines are idempotent, a backfill is simply running the process over a past date range. That predictability is the real payoff: fewer late-night repairs, fewer special scripts and data that people can trust.

This article offers general engineering perspective. It does not describe a specific client engagement.