Data
AI
The Stack Underneath


You build a data pipeline by working through ten stages in sequence: define the business goal, identify your sources, choose how often data moves, design the architecture, then build ingestion, transformation, storage, orchestration, and monitoring before testing the whole thing in a staging environment. Each stage depends on the ones before it, which is why skipping ahead is the most common way pipelines end up needing a rebuild.
The sequence matters more than any single tool choice. A team that picks its architecture before understanding its sources ends up forcing data into a design that doesn't fit. A team that builds ingestion before deciding on batch or streaming rebuilds that layer twice. The order below exists because each step answers a question the next step depends on, and the whole thing sits inside the broader work of data pipeline development that keeps it running long after launch.
Here's the full sequence before we go deep on each one:
Define the business goal
Identify every data source
Choose batch, streaming, or hybrid
Design the pipeline architecture
Build the ingestion layer
Transform and validate the data
Store data in the right destination
Orchestrate the workflow
Monitor everything
Test before production
None of these are optional. You can move fast through the early ones on a simple pipeline, but you can't skip them.
Start with the decision the data has to support, not the technology that moves it. Before anyone opens a tool, you need one clear answer: what will someone do differently because this pipeline exists? A pipeline built without that answer is a pipeline that gets rebuilt the moment someone finally asks it.
The goal drives every choice downstream. "The operations team needs yesterday's production numbers by 7 a.m." tells you the freshness requirement, which tells you whether you need batch or streaming, which shapes the architecture, which narrows the tools. Skip this and you're guessing at all four.
Three questions pin it down:
Who consumes the output, and what do they do with it? A dashboard an analyst checks weekly and a fraud model that blocks transactions in real time are not the same build. The consumer sets the stakes.
How fresh does the data need to be? Be honest here, not aspirational. "Real time" sounds impressive and doubles your cost. Most decisions can wait an hour. Some can't wait a second. The gap between those two answers is enormous.
What does "correct" mean for this data? A marketing report can tolerate a rounding error. A pharma batch record cannot lose a single reading. Correctness defines how hard your validation has to work later.
Here's where teams get it wrong. They answer these questions vaguely, "we need better visibility into sales," and call it a spec. That's not a goal, it's a wish. Push until the answer is specific enough to build against. "Regional sales leads need daily revenue by store, accurate to the closed transaction, available by 8 a.m." is a goal. You can design against that. You cannot design against "better visibility."
Most of the pipeline falls out of this one page. Get it right and the later steps mostly settle themselves. Get it wrong and you'll feel it in week three.
You cannot design a pipeline until you know exactly what it's pulling from, and the word that matters here is exactly. Not "our CRM and some spreadsheets." Every source, profiled, with its quirks written down. The surprises you miss at this stage are the ones that blow up your timeline in week three.
For each source, get specific on four things:
Format: JSON from an API, rows from a Postgres database, a CSV dumped nightly to an SFTP server. Each one is a different integration problem.
Volume: A thousand records a day and ten million a day are not the same build, even from the same source type.
Frequency of change: How often the data updates, and just as important, how often the source's structure changes. A schema that shifts without warning is the most common reason pipelines break.
Reliability: Does the source go down? Send duplicates? Return yesterday's data when it's slow? Assume it does all three.
Here's the trap. A utility pulling meter readings from three vendors with three different formats doesn't have one integration, it has three, each with its own failure modes. Teams scope that as a single line item and then wonder why the estimate was off by a month. Count the real surface area, not the number of logos on the diagram.
Write it all down in one place. This source inventory becomes the input for every decision after it, how fresh the data can be, which architecture fits, how hard your ingestion layer has to work. Skip the profiling and you're designing blind.
This is the first big architectural fork, and it comes down to one question: how long can a decision wait? Batch moves data in scheduled groups, an hour, a night, whatever the business tolerates. Streaming processes each record as it arrives, in seconds or less. Hybrid runs both paths for cases that need fast answers now and correct ones later.
Most teams reach for streaming because it sounds better, then pay to build and run a real-time system a nightly batch would have served. That's the expensive mistake. Streaming costs more to build, is harder to debug, and runs continuously whether or not anything's happening.
Here's how the three compare on what actually drives the decision:
|
Batch |
Streaming |
Hybrid | |
|
Latency |
Minutes to hours |
Seconds or less |
Both, by path |
|
Cost |
Lower |
Higher |
Highest |
|
Complexity |
Simple to build and debug |
Hard on both |
Two systems to maintain |
|
Fits |
Reports, syncs, backfills |
Alerts, fraud, live monitoring |
Needs speed and accuracy |
Batch is the right default, and it handles more real-world pipelines than people expect. A retailer syncing inventory hourly, a finance team closing the books nightly, none of that needs per-second freshness. Streaming earns its place only when the delay itself is the risk, like an energy grid watching for load imbalance or a fraud check that has to clear before a transaction completes. If your use case genuinely can't tolerate a wait, the design detail lives in our guide to real-time data pipelines.
Start with batch. You can always add a streaming path later for the specific feeds that need it. Going the other way, ripping streaming out because you overbuilt, is the rebuild nobody budgets for.
With your sources mapped and your freshness call made, you can now design the data pipeline architecture, the blueprint for how data flows through the system, where it gets processed, and what happens when a source fails at 2 a.m. This is the part you can't easily change later. Tools you can swap and code you can refactor, but the shape of how data moves gets locked in early and is expensive to undo.
Your work in Steps 2 and 3 already made the big calls. The freshness requirement picked your pattern, batch, streaming, lambda, kappa, or lakehouse. The source inventory told you how many integration points the design has to hold. What's left is deciding how the layers connect and where the pressure points sit.
Good data pipeline design comes down to designing for the failure you know is coming, not the happy path. Three decisions carry the most weight:
Where transformation happens. Before data lands or after it's stored. This is the ETL-versus-ELT call, and it changes cost, speed, and how flexible you are later.
How failure gets handled. What retries, what recovers, what quarantines a bad record instead of passing it downstream to break something.
Where it has to scale. The stage most likely to choke under 10x volume is the one to design for parallelism now, because retrofitting it later is a rebuild.
The patterns, the reference diagram, and the deeper trade-offs behind each one live in our full breakdown of data pipeline architecture. For the build, the point is this: settle these three before you write a line of ingestion code. A design that assumes sources behave and volume stays flat works in testing and breaks in production.
Now you connect to the sources and get data flowing in, on a schedule or as a continuous stream. This is the first code you write, and the rule that matters is simple. Build it for the source misbehaving, not the source cooperating.
Ingestion that assumes clean input works in testing and breaks in week three. A source will go down mid-pull, send the same records twice, or change its schema without warning, and usually it does all three before the quarter's out. So build for it from the start: retry on failure, handle duplicates so a rerun doesn't double your data, and validate the incoming shape so a renamed column gets flagged instead of silently corrupting everything downstream.
The teams that skip this ship fast and pay later. The bad night comes, ingestion falls over, and what should have been an automatic retry becomes a 6 a.m. manual cleanup. Expensive, and entirely avoidable.
Raw data is almost never usable as it arrives. Step 6 is where you clean it, standardize formats, join sources, and apply the business logic that turns three vendors' messy exports into one table someone can trust. This is where data quality is won or lost.
The first decision is when the transformation runs:
ETL transforms the data before it lands. Best for regulated pipelines where only clean, validated records are allowed into storage.
ELT loads it raw, then transforms inside the warehouse. Best for modern cloud stacks, where the warehouse has the compute and you keep raw data to reprocess anytime the logic changes.
For most cloud builds, ELT wins. The full breakdown of which fits your case is in our guide to ETL vs ELT.
Then comes validation, and this is the part teams bolt on too late. Check the data as it moves, not after it's landed. At minimum, catch:
Nulls where a value is required
Out-of-range numbers and impossible dates
Broken or shifted formats from a changed source
Duplicate records from a retried pull
Validation built into this layer stops bad records at the door. Add it afterward and the bad data has already spread across every downstream table before anyone notices.
A pharma company transforming lab records does most of its compliance work right here. Standardize the timestamps, drop the malformed readings, reconcile the batch IDs, then load. Skip the middle step and you've just moved garbage faster.
Transformed data needs somewhere to land, and the choice comes down to what the data feeds and how it gets queried. Three options cover most builds:
|
Destination |
Holds |
Best for |
|
Data warehouse |
Structured, query-ready data |
BI, dashboards, reporting |
|
Data lake |
Raw and semi-structured data |
ML, cheap bulk storage, mixed formats |
|
Lakehouse |
Both, in one layer |
Teams running analytics and ML without two systems |
Match the destination to the consumer you defined back in Step 1. A finance team living in dashboards needs a warehouse. A data science team training models needs the raw flexibility of a lake. A team doing both, and not wanting to copy data between two systems, is where the lakehouse earns its place, which is the ground Databricks and Snowflake both compete on.
One rule holds across all three. The destination is an architecture decision, not an afterthought, because it dictates how the data gets queried and how fast. Pick it to fit the question being asked, not because it's the platform you already happen to run.
Orchestration is the coordinator that decides what runs, in what order, and what happens when a step fails. Without it, a pipeline is just a pile of scripts hoping to fire in sequence.
This is the layer that turns those scripts into a system. It runs Step 5's ingestion, then Step 6's transformation, then Step 7's load in the right order, waits for each to finish, and retries or halts cleanly when one errors out instead of letting a half-finished run corrupt everything downstream.
The decision that matters here is what happens on failure. A job dies at 3 a.m., and either the orchestrator retries and picks up where it stopped, or someone restarts the whole thing by hand in the morning. Design for the first. Idempotency belongs here too, so a rerun produces the same result instead of doubling your data.
A pipeline you can't see into is one you'll debug blind. Monitoring is the layer that tells you the pipeline is healthy, or that it isn't, and it's the component teams cut first to hit a deadline and regret most.
The danger isn't the pipeline that crashes loudly. It's the one that keeps running while quietly dropping records or duplicating rows, because bad data reaches a dashboard and someone acts on it before anyone notices. We've seen a broken feed run two weeks before it was caught. By then the wrong numbers were already in reports that went to leadership.
Instrument three things from day one:
Failures — jobs that error, so you hear it from an alert, not your boss
Latency — runs drifting slower, the early warning that volume is outgrowing the design
Data volume — sudden drops or spikes that signal a source broke or started duplicating
Set alerts on all three. The goal is simple: find out about a failure from your own dashboard, before a stakeholder finds out for you.
Testing a data engineering pipeline is not the same as testing an app, and assuming it is gets teams burned. App tests check that code does what you wrote. Pipeline tests check that code does what you wrote and that the data flowing through it is correct, because a pipeline can run flawlessly and still deliver wrong numbers.
Run it against real conditions in a staging environment before it touches production. Test for four things:
Correctness — does the output match a known-good result you can verify by hand?
Failure recovery — kill a job mid-run and confirm it retries or resumes without duplicating data
Bad input — feed it nulls, a changed schema, a duplicate batch, and confirm validation catches them
Scale — run it at the volume you expect in a year, not the volume you have today
That third one is where most pipelines fall over. Everything works on clean sample data, then a real source sends something malformed in week two and the whole thing tips. Test the ugly cases on purpose, because production will find them for you if you don't.
Only when it holds up under all four does it earn a place in production. Shipping an untested pipeline means finding out it's broken from the person who acted on its bad output. Expensive, and the whole reason this step exists.
The ten steps get a pipeline built. These are the problems that show up anyway, and anticipating them is half of data pipeline development done right. Almost every one traces back to a decision made early and paid for late.
A source adds a column, renames a field, or switches a data type, and the pipeline that assumed the old shape falls over. This is the single most common production failure. Validate schemas at ingestion and quarantine the surprises instead of passing them straight downstream.
The pipeline keeps running while quietly dropping or duplicating records, so bad data reaches a report before anyone notices. This is a monitoring gap, not a code bug. If the system can't tell you the data is wrong, the person acting on it will.
A pipeline built for a million rows a day chokes at ten million, usually at one stage that can't run in parallel. Retrofitting parallelism into a design that never planned for it is expensive. Assume growth up front instead of rebuilding under load.
Three vendors, three formats, three sets of quirks, scoped as a single integration. This is where timelines slip. Count the real integration surface back in Step 2, not the number of logos on the diagram.
Teams attempt all ten steps for every source in one pass and stall halfway. Ship one source end to end, prove it works, then add the next. A narrow pipeline running beats a broad one half-built.
None of these are exotic. They break pipelines across every industry in the same predictable ways, which is exactly why you design against them before they arrive.
Take a mid-sized retailer that wants regional managers to see yesterday's sales by store, accurate to the closed transaction, in a dashboard by 8 a.m. That single goal, straight from Step 1, decides everything below it.
The sources are three: a Postgres database behind the point-of-sale system, a SaaS inventory tool with a REST API, and a nightly CSV of returns dumped to cloud storage. None of it needs to be live. An 8 a.m. dashboard means a nightly batch run is enough, so there's no streaming to build and no streaming cost to carry.
Here's how the data moves through it:
Ingestion pulls from all three sources on a nightly schedule, with retries in case the API is down and duplicate handling so a rerun doesn't double the numbers.
Transformation runs in the warehouse, ELT style. Raw data lands first, then dbt models clean it, join the three sources on store and date, and reconcile the returns against sales.
Validation checks the output before it's trusted, no null store IDs, no negative quantities, row counts within expected range.
Storage lands the modeled data in a cloud warehouse like Snowflake, shaped for the exact queries the dashboard runs.
Orchestration through Airflow runs the stages in order, waits for each, and alerts if one fails overnight.
Monitoring tracks the run's success, its latency, and the row volume, so a broken source is caught before 8 a.m., not after.
The result is a pipeline a small team can run and reason about. It uses a modern cloud stack, but it's deliberately boring, batch over streaming, ELT over hand-rolled transforms, a handful of proven tools over a sprawling one. That restraint is the point. The best data engineering pipeline for this job is the simplest one that meets the 8 a.m. deadline, not the most impressive one you could build.
TThere's no single right stack, only the smallest one that covers what you mapped in Steps 1 through 4. The landscape is crowded and most tools overlap, which tempts teams into assembling ten when three would do. Every tool you add is another thing to patch and debug, so aim for coverage, not collection.
You're picking one tool per job:
|
Job |
Common picks |
|
Ingestion |
Fivetran, Airbyte, custom scripts |
|
Transformation |
dbt, Apache Spark |
|
Storage |
Snowflake, BigQuery, Databricks |
|
Orchestration |
Apache Airflow |
|
Monitoring |
Built-in checks, observability tools |
Two forces decide the picks. Your cloud, since a team on AWS reaches for its native services first. And your engineering depth, because open-source tools like Spark and Airflow cost nothing to license but you run them yourself, while managed services like Fivetran flip that, higher cost, almost no infrastructure to babysit. Neither is better in the abstract; it depends on how many engineers you have to keep it running.
The full tool-by-tool comparison is in our breakdown of data pipeline tools. For the build, the rule holds: pick the fewest tools that cover the jobs above, and add more only when a real limit forces you to.
If there's one thing to carry out of these ten steps, it's that building a data pipeline is a sequence, and the order is the whole point. The decisions that shape everything come first, what the data is for, where it comes from, and how fresh it truly needs to be. Answer those three honestly and the architecture, the tools, and the batch-versus-streaming call mostly settle themselves. Get them wrong and you feel it downstream, in the layer that's hardest to change.
So start there, before you open a single tool. Write down who consumes the output, how current it has to be, and what "correct" means for your data. That one page decides more than any tool comparison will.
The rest is discipline. Build ingestion for the source that misbehaves, win data quality in the transform, and instrument monitoring before go-live, not after the first bad night. None of it is exotic. It's just done in order, by someone who assumed things would break and designed for it.
If the answers point to a build bigger than your team can carry, that's the point where our data engineering services team can map the architecture with you and give you a real scope instead of a guess.
A simple batch pipeline from one or two clean sources can be running in a few days, while a production-grade pipeline pulling from many messy sources with full monitoring takes several weeks. The biggest time driver isn't the tooling, it's the number and reliability of your sources. Mapping those in Step 2 is what keeps the timeline honest.
You need SQL, at least one programming language like Python, and a working understanding of how data warehouses and orchestration tools behave. Beyond the technical side, the harder skill is judgment, knowing when batch beats streaming, when to keep the stack small, and where a design will break under load. That judgment is usually what separates a pipeline that lasts from one that gets rebuilt.
Handling the sources, not the code. A source that changes its schema without warning, sends duplicates, or goes down mid-pull is the most common reason pipelines break in production. Building ingestion and validation to expect that misbehavior, rather than assuming clean input, is the part teams underestimate most.
Yes, no-code and low-code tools like Fivetran and Airbyte can move data from source to warehouse with almost no engineering. They work well for standard sources and simple transformations, but custom logic, unusual sources, or fine-grained failure handling still need code. Most real pipelines end up as a mix of managed connectors and custom work.
Cost depends far more on architecture than on tools, and the batch-versus-streaming choice is the biggest lever. A nightly batch pipeline on managed services can run for a few hundred dollars a month, while a real-time streaming system that runs continuously costs several times more to operate. Keeping the stack small and defaulting to batch unless the use case demands otherwise is what keeps the bill reasonable.
You might also like