Skip to main content

Data Pipeline Engineering: Production Patterns That Survive the First Year

ETL vs ELT tradeoffs, data contracts in CI, schema evolution without pipeline fires, and the failure taxonomy from operating pipelines across fintech and telecom at scale.

13 min read

Summary#

A pipeline that passes every test on day one can break silently on day ninety when a source system adds a nullable column. This article, part of the data architecture series, covers the patterns that survive first contact with production: ETL versus ELT tradeoffs, data contracts enforced in CI, schema evolution strategies that do not require a war room, and a failure taxonomy drawn from operating pipelines across fintech, telecom, and gaming workloads. The goal is not to pick the right tool. It is to build pipelines that keep working after the team that built them stops watching.

The Pipeline That Looked Fine for Six Months#

A quarterly compliance report started returning fewer rows than expected. Not zero, not an error. Just 11% fewer. The pipeline had been running for six months without incident. Every Airflow DAG showed green. Every dbt test passed.

The root cause took two days to find. An upstream team had added a region_code column to the source table with a default value of NULL. The ingestion layer picked it up correctly. The staging model cast it to a string. The intermediate join, which filtered on region_code IS NOT NULL, silently dropped 11% of records that had always been there under the old schema.

No alert fired because the volume check had a 15% threshold. No test caught it because the test fixtures predated the schema change. The pipeline was not broken. It was working exactly as coded, against data that no longer matched the assumptions baked into the SQL.

This is the pattern that recurs across every data platform I have operated. The initial build is the easy part. The hard part is surviving the changes that nobody tells you about.

ETL, ELT, and the Third Pattern#

The ETL versus ELT debate is mostly settled for cloud warehouse workloads. ELT wins when storage is cheap and compute is elastic, which describes every major cloud warehouse in 2026. Load the raw data first, transform it in the warehouse where the compute engine is optimised for exactly that operation.

ETL remains the correct choice in three scenarios. First, when sensitive data must be transformed before it lands in a shared environment. In fintech, PII and cardholder data often cannot touch a general-purpose warehouse in raw form. The transform happens in transit, not after landing. Second, when bandwidth constraints make raw data transfer impractical. A 40 TB daily export from a legacy Oracle system is cheaper to aggregate at the source than to ship in full. Third, when regulatory requirements demand that business logic is applied before data crosses a trust boundary.

Most production platforms use both. The pattern that rarely gets discussed is the hybrid: raw data lands in an object store (S3, GCS), critical business logic transforms run in a lightweight processing layer (Spark, Flink) before the data enters the warehouse, and the remaining transformations happen inside the warehouse via dbt. This is neither pure ETL nor pure ELT. It is the pragmatic default for regulated industries where you cannot load everything raw and sort it out later.

sql
-- Hybrid pattern: PII stripped before warehouse load
-- Raw → S3 → Spark (mask PII) → Snowflake staging → dbt marts

-- In the Spark layer:
-- email → SHA-256 hash
-- card_number → tokenized via vault API
-- ip_address → truncated to /24

-- In the dbt layer (post-load):
-- Joins, aggregations, business logic
-- No PII present at this stage

The decision is not philosophical. It is driven by data classification. If the source contains restricted data, transform before load. If it does not, load then transform.

Data Contracts: From Conference Theory to CI Pipeline#

A data contract is not a document. It is an executable specification that defines what a dataset promises to its consumers: the schema, the freshness guarantee, the expected volume range, and the semantic meaning of each field.

The concept has been circulating at conferences since 2022, but adoption has lagged. The data contracts market for AI applications is growing at 23.1% CAGR, from $1.28 billion in 2025 to $1.57 billion in 2026 (Research and Markets, 2026). The tooling exists. The discipline often does not.

In practice, a data contract is a YAML or Protobuf definition that lives alongside the pipeline code, is validated in CI, and gates deployment.

yaml
# contracts/orders_v2.yaml
contract:
  name: orders
  version: 2
  owner: payments-team
  schema:
    - name: order_id
      type: string
      required: true
    - name: amount_cents
      type: integer
      required: true
      constraints:
        min: 0
    - name: created_at
      type: timestamp
      freshness: "< 15 minutes"
  volume:
    daily_min: 10000
    daily_max: 500000
  sla:
    availability: 99.9%

The enforcement mechanism matters more than the specification format. A contract that is not checked in CI is a suggestion. The CI step validates three things: the schema matches the contract (column names, types, nullability), the freshness SLA is achievable given the pipeline's schedule, and the volume bounds are consistent with the source system's documented throughput.

When a contract violation is detected, the pipeline should fail at the source, not propagate corrupted data downstream. This is the opposite of what most teams do. Most teams discover contract violations when a dashboard shows unexpected numbers three days later.

Airbnb's Stage-Check-Exchange pattern (documented in their engineering blog) formalises this: write data to a staging table, run automated quality checks, and only exchange the staging table with the production table after checks pass. The exchange is atomic. If checks fail, the production table retains the previous version.

Schema Evolution Without Pipeline Fires#

Schema changes from upstream systems are the single most common source of pipeline failures. A field gets renamed. A type changes from integer to string. A new column appears with unexpected null values. Each of these is routine from the source team's perspective and catastrophic from the pipeline team's perspective.

The metadata-driven ingestion pattern reduces schema evolution costs by up to 35% in enterprise-scale platforms. The idea is straightforward: instead of hardcoding column names in the ingestion layer, read the schema from a registry or from the source system's metadata endpoint, and map columns dynamically.

python
# Metadata-driven ingestion
# Schema is read from source, not hardcoded

def ingest_table(source_conn, table_name, registry):
    current_schema = source_conn.get_schema(table_name)
    registered_schema = registry.get(table_name)

    diff = compare_schemas(current_schema, registered_schema)

    if diff.has_breaking_changes():
        raise SchemaBreakingChange(
            table=table_name,
            changes=diff.breaking,
        )

    if diff.has_additive_changes():
        registry.evolve(table_name, current_schema)
        notify_consumers(table_name, diff.additive)

    return extract(source_conn, table_name, current_schema)

The key distinction is between additive and breaking changes. A new nullable column is additive; it should be ingested automatically and downstream consumers should handle it gracefully. A type change on an existing column is breaking; it should fail the pipeline and alert the team.

Schema registries (Confluent Schema Registry, AWS Glue Schema Registry) enforce compatibility modes: backward compatible (new schema can read old data), forward compatible (old schema can read new data), and full compatible (both directions). For most pipelines, backward compatibility is the right default. It means consumers can always read data produced by any version of the producer.

Testing Pipelines Like Software#

Schelter et al. introduced the concept of "unit tests for data" at VLDB 2018, presenting a declarative API that translates data quality constraints into aggregation queries on Apache Spark. The approach supports incremental validation and ML-based anomaly detection. The paper is worth reading for the constraint taxonomy alone.

In practice, the testing pyramid for data pipelines has three layers.

Unit tests validate individual transformations. A dbt model that calculates revenue should have a test with known inputs and expected outputs. This catches logic errors before they reach production.

Integration tests validate the pipeline end-to-end with fixture data. The fixtures should represent realistic edge cases: null values in unexpected columns, timestamps in different timezones, duplicate records, and records at volume boundaries. The fixture data must be updated when the source schema changes, which is why most teams eventually automate fixture generation from production samples (with PII stripped).

Data quality gates sit at stage boundaries and run in production. They check freshness (when was this table last updated?), volume (is the row count within expected bounds?), schema (do the columns match the contract?), and distribution (are the value distributions statistically consistent with recent history?). Gates that detect critical violations should block downstream processing. Gates that detect anomalies should alert but not block.

Monte Carlo's analysis of 11 million monitored tables found that pipeline execution faults account for 26.2% of all data quality issues, making them the most common root cause. Real-world variation accounts for 20%, and intentional changes (backfills, migrations) account for 14.2%. Roughly 34% of flagged incidents are not actual incidents (Monte Carlo, 2025).

The implication is clear: testing must account for legitimate variation, not just bugs. A volume drop of 8% on a Sunday is normal for many B2B datasets. A volume drop of 8% on a Tuesday is a signal. The testing framework needs to know the difference.

Cost Engineering for Data Pipelines#

Pipeline costs become a board-level conversation faster than most teams expect. The dbt Labs 2024 State of Analytics Engineering survey found that organisations allocate 60 to 70% of total data budgets to data engineering activities: ingestion, transformation, orchestration, and infrastructure.

The most common cost mistake is running full refreshes on tables that could be processed incrementally. An incremental model in dbt that processes only new and changed records can reduce warehouse compute by an order of magnitude on large fact tables. The tradeoff is complexity: incremental models require careful handling of late-arriving data and idempotent merge logic.

Per-pipeline cost attribution is the foundation of cost engineering. If you cannot tell the CFO which pipeline costs EUR 4,200 per month and why, you cannot defend your infrastructure budget. Snowflake's resource monitors and Redshift's query cost attribution make this possible, but the tagging discipline must be enforced from day one.

One pattern that pays for itself quickly: right-sizing warehouse compute. A clustering key on event_date dropped a query from 45 seconds to 8 seconds on a medium Snowflake warehouse. Auto-suspend configured at 60 seconds for development and 300 seconds for production reduced warehouse usage by 45% in one team I worked with. These are not optimisations you discover in month one. They are the tuning that happens in month four when the bills arrive.

What Breaks in Production and When#

After operating pipelines across fintech, telecom, and gaming workloads, the failure taxonomy is predictable. The failures are not exotic. They are mundane, repetitive, and preventable with the right guardrails.

Source schema drift is the most common. A field gets renamed, a type changes, a new column appears with null values. The fix is the metadata-driven ingestion pattern described above, combined with schema contracts.

Volume spikes follow business cycles. Black Friday, end-of-quarter reporting, game launch events. If your pipeline is sized for average throughput, it will fall behind on peak days. The fix is autoscaling where the platform supports it and capacity planning where it does not.

Dependency chain failures cascade. DAG A feeds DAG B, which feeds DAG C. If DAG A fails at 2am, DAGs B and C will run on stale data at 6am unless they explicitly check that their upstream dependency succeeded. Airflow's ExternalTaskSensor and dbt's source freshness checks exist for exactly this reason. The mistake is not using them.

Silent data corruption is the hardest to detect. The pipeline runs successfully. The row counts look normal. But a timezone conversion is off by one hour, or a currency conversion uses yesterday's exchange rate instead of today's. These failures only surface when a human looks at the output and notices something feels wrong. The fix is golden test sets: a small, curated set of records with known correct outputs, validated on every pipeline run.

Airflow-specific failures deserve mention. DAG import errors (syntax errors in Python files) silently prevent the DAG from loading. The scheduler marks no error because it never saw the DAG. The airflow dags list-import-errors command is the diagnostic that most teams learn about too late. Worker pool exhaustion, where the default parallelism=32 per scheduler limits concurrent tasks, causes tasks to queue indefinitely during peak hours. And metadata database bloat, where the PostgreSQL metadata store slows down as task instance history grows, degrades the scheduler and the web UI over months.

The data observability engineering guide covers the monitoring side of these failure modes. This article covers building the guardrails that prevent them.

The Honest Assessment#

The patterns in this article are not novel. Data contracts, schema registries, incremental processing, and quality gates have all been discussed at conferences for years. The gap is not in knowledge. It is in discipline.

The dbt Labs survey found that 57% of data professionals cite poor data quality as their predominant issue, up from 41% in 2022. Data professionals spend roughly 40% of their time on data quality triage (Monte Carlo, 2025). The data is getting worse, not better, despite better tooling.

The teams that operate reliable pipelines share one trait: they treat their data platform the same way application teams treat production services. Contracts, tests, monitoring, incident response, and post-mortems. The same database selection decisions that shape your warehouse also shape your pipeline's reliability. And the same architecture patterns that guide your platform design must extend to the pipelines that move data through it.

Build the pipeline for month six, not day one.

Frequently Asked Questions#

What is a data contract and how do you enforce one in production?#

A data contract defines what a dataset promises: schema, freshness, volume, and semantic meaning. Enforce contracts by codifying them in a schema registry or YAML definitions, validating them in CI before deployment, and gating pipeline runs on contract compliance. Violations should fail fast at the source, not propagate downstream.

Should you use ETL or ELT for enterprise data pipelines?#

ELT is the default for cloud warehouse workloads because storage is cheap and compute is elastic. ETL remains the right choice when you need to transform sensitive data before it lands in a shared warehouse, when bandwidth constraints make raw data transfer impractical, or when business logic must be applied in-flight for regulatory reasons. Most production platforms use both.

How do you test data pipelines before they reach production?#

Apply the same testing pyramid as software engineering. Unit test individual transformations with known input/output pairs. Integration test with fixture data that represents realistic edge cases. Add data quality gates at stage boundaries that block on critical failures and alert on anomalies. Test for schema drift by simulating column additions, type changes, and null introduction.

Emanuel Mallia
Emanuel Mallia

Enterprise Data & AI Leader

Share
Emanuel Mallia, Enterprise Data & AI Leader
Emanuel Mallia

Leads enterprise Data & AI programmes from strategy through production. 14+ years delivering data platforms, enterprise data warehouses, and AI systems across fintech, telecoms, gaming, and S&P 500 companies.

More about Emanuel

Have Questions?

If you'd like to discuss this topic or explore how I can help with your AI and data initiatives, let's connect.