<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>OLake Learn</title>
        <link>https://olake.io/learn/</link>
        <description>OLake Blog</description>
        <lastBuildDate>Sat, 03 Oct 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[What Is a Data Pipeline? A Plain Guide]]></title>
            <link>https://olake.io/learn/what-is-a-data-pipeline/</link>
            <guid>https://olake.io/learn/what-is-a-data-pipeline/</guid>
            <pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[What is a data pipeline? Its parts, six types compared with their limits, a worked example, and which tools do which job. Dated October 2026.]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="eager" src="https://olake.io/img/blog/cover/what-is-a-data-pipeline-cover.webp" alt="Cover for what is a data pipeline showing sources flowing through a pipeline into a warehouse or lake" width="1920" height="1080" fetchpriority="high" class="img_ev3q"></p>
<section class="olake-tldr" aria-label="Key takeaways"><p class="olake-tldr__label"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="M215.79,118.17a8,8,0,0,0-5-5.66L153.18,90.9l14.66-73.33a8,8,0,0,0-13.69-7l-112,120a8,8,0,0,0,3,13l57.63,21.61L88.16,238.43a8,8,0,0,0,13.69,7l112-120A8,8,0,0,0,215.79,118.17ZM109.37,214l10.47-52.38a8,8,0,0,0-5-9.06L62,132.71l84.62-90.66L136.16,94.43a8,8,0,0,0,5,9.06l52.8,19.8Z"></path></svg><span>Key takeaways</span></p><div class="olake-tldr__body"><p>A data pipeline is just automated steps that move your data from where it's created to where people actually use it, like a report or a model. Most of them copy data out of an app or database, tidy it up, and drop it into a warehouse. The big choice is how fresh the data needs to be: a nightly batch is the simplest, and streaming is the fastest but never stops running.</p><ul>
<li class=""><strong>A data pipeline moves data from a source to a destination.</strong> AWS's page defines it as a series of processing steps that prepare data for analysis. That is one vendor's definition, not a standard.</li>
<li class=""><strong>A pipeline doesn't have to reshape data.</strong> IBM's page says one may simply move data from one system to another.</li>
<li class=""><strong>The pipeline types answer four different questions.</strong> Batch and streaming are about timing, ETL and ELT about order, change data capture about finding changes, and reverse ETL about direction. Real designs combine them.</li>
<li class=""><strong>Every type has a named cost.</strong> Batch is stale, streaming never stops running, and reading a database's change log needs setup on the source.</li>
<li class=""><strong>A pipeline that runs is not yet production-ready.</strong> It also needs a scheduler, safe reruns and alerts, and loading, reshaping and scheduling are often three different tools.</li>
</ul></div></section>
<p>We checked the facts and tool details here against each vendor's own pages on October 1, 2026. Definitions and feature claims below are the vendors' own wording, and we have not tested any of them. Tools change often, so confirm anything before you spend money on it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-what-is-a-data-pipeline">So, what is a data pipeline?<a href="https://olake.io/learn/what-is-a-data-pipeline/#so-what-is-a-data-pipeline" class="hash-link" aria-label="Direct link to So, what is a data pipeline?" title="Direct link to So, what is a data pipeline?" translate="no">​</a></h2>
<p>Think of it as a delivery route for data. It starts in a source, such as a shop's database or a payment app. The end point is a destination, such as a warehouse (a database built for reports), a data lake (cheap file storage that many tools can read), or a lakehouse (a data lake organised so tools can query it like a warehouse).</p>
<p>AWS's page uses a plain picture: <a href="https://aws.amazon.com/what-is/data-pipeline/" target="_blank" rel="noopener noreferrer" class="">like water moving from a reservoir to your taps</a>, a pipeline moves data from where it is collected to where it is stored. Its definition is a series of processing steps that prepare enterprise data for analysis. AWS sells data services, so read this as AWS's wording, not settled fact.</p>
<p><img decoding="async" loading="lazy" src="https://olake.io/img/blog/2026/10/aws-what-is-data-pipeline.webp" alt="AWS page defining a data pipeline as a series of processing steps that prepare enterprise data for analysis" width="1600" height="471" class="img_ev3q"></p>
<p><em>AWS's own definition, from its "What is a Data Pipeline?" page, October 2026.</em></p>
<p>Two words cause most of the confusion, so let's sort them out now. <strong>Pipeline</strong> is the whole path. <strong>ETL</strong> (extract, transform, load) is one way to build that path, where data gets reshaped before it lands.</p>
<p>International Business Machines (IBM) says <a href="https://www.ibm.com/think/topics/data-pipeline" target="_blank" rel="noopener noreferrer" class="">ETL follows a fixed extract, transform, load order</a>, while a data pipeline "may simply move data from one system to another" without transformations. That is IBM's definition, and other vendors draw the line differently. On IBM's reading, every ETL pipeline is a data pipeline, but not the other way round.</p>
<p>One more trap is product naming. In Azure Data Factory, Microsoft uses "pipeline" for <a href="https://learn.microsoft.com/en-us/azure/data-factory/concepts-pipelines-activities" target="_blank" rel="noopener noreferrer" class="">a logical grouping of activities that together perform a task</a>. That's one product's object, not the general idea.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-parts-of-a-data-pipeline">The parts of a data pipeline<a href="https://olake.io/learn/what-is-a-data-pipeline/#the-parts-of-a-data-pipeline" class="hash-link" aria-label="Direct link to The parts of a data pipeline" title="Direct link to The parts of a data pipeline" translate="no">​</a></h2>
<p>IBM says three core stages make up a pipeline: data ingestion, data transformation and data storage. Transformation is the optional one, since a pipeline may simply move data.</p>
<p>Ingestion means copying data out of its sources. Cleaning it and changing its shape is transformation, and storage means putting it where people can use it.</p>
<p>Here's the part people forget. A fourth piece sits beside those three.</p>
<p>Something has to decide when each step runs, retry it when it fails, and warn a person when it keeps failing. AWS's page says a well-designed pipeline keeps working even if individual components fail, and that you must protect data accuracy despite interruptions. That is a design goal, and no vendor page proves a given tool meets it.</p>
<p><img decoding="async" loading="lazy" src="https://olake.io/img/blog/2026/10/what-is-a-data-pipeline-stages.webp" alt="Data flows from sources through ingestion and transformation into storage, with scheduling and monitoring running alongside every step" width="1600" height="720" class="img_ev3q"></p>
<p>Most real problems live in the lower lane of that diagram. A one-off copy is easy, but a copy that runs every day for two years, through failed runs and changed columns, is the hard part.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-data-pipelines-used-for">What are data pipelines used for?<a href="https://olake.io/learn/what-is-a-data-pipeline/#what-are-data-pipelines-used-for" class="hash-link" aria-label="Direct link to What are data pipelines used for?" title="Direct link to What are data pipelines used for?" translate="no">​</a></h2>
<p>Common uses, per IBM, include fraud detection, exploratory analysis, dashboards, machine learning and data quality monitoring and more. The use decides the speed you need. Fraud checks need seconds, while a dashboard usually doesn't.</p>
<p>AWS adds that pipelines handle structured data (database rows), semi-structured data (such as JSON files) and unstructured data (such as images). Check that a tool reads the shape of data you have.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="data-pipeline-types-compared">Data pipeline types, compared<a href="https://olake.io/learn/what-is-a-data-pipeline/#data-pipeline-types-compared" class="hash-link" aria-label="Direct link to Data pipeline types, compared" title="Direct link to Data pipeline types, compared" translate="no">​</a></h2>
<p>Types aren't one tidy list, because they answer different questions. Batch and streaming answer "how often." ETL and ELT (extract, load, transform) answer "where does the reshaping happen."</p>
<p>Change data capture (CDC) answers "how do we find what changed," and reverse ETL answers "which way does the data flow."</p>
<p>Below are six common kinds, each with its limit.</p>
<table><thead><tr><th>Type</th><th>What it does</th><th>Better when</th><th>Named limit</th></tr></thead><tbody><tr><td>Batch</td><td>Loads data in groups at set times, often off-peak</td><td>Reports can be a few hours or a day old</td><td>Data is only as fresh as the last successful run</td></tr><tr><td>Streaming</td><td>Processes events continuously as they happen</td><td>You must react in seconds</td><td>Runs continuously instead of in short scheduled runs</td></tr><tr><td>Change data capture</td><td>Copies each insert, update and delete from a database</td><td>You need changes without re-copying whole tables</td><td>The source database needs setup, and in PostgreSQL a stalled reader can fill its disk</td></tr><tr><td>ETL</td><td>Reshapes data before loading</td><td>You must mask or filter data before it lands</td><td>Data must pass through the reshaping rules before it reaches the destination</td></tr><tr><td>ELT</td><td>Loads raw data first, reshapes it in the destination</td><td>The destination is a strong warehouse or lakehouse</td><td>Unpredictable data volumes can bring unexpected costs later</td></tr><tr><td>Reverse ETL</td><td>Sends modelled data from the warehouse back into business tools</td><td>Sales or support teams need warehouse numbers in their own tools</td><td>It is only as fresh as the warehouse data it reads</td></tr></tbody></table>
<p>According to IBM, <strong>batch</strong> loads batches of data at set intervals, typically off-peak. IBM says <strong>streaming</strong> pipelines, also called event-driven architectures, continuously process events from sources such as sensors or user interactions in an app. AWS adds that batch pipelines run infrequently while stream processing pipelines run continuously.</p>
<p><strong>Change data capture</strong> deserves a longer note, because it's the type most people haven't met. Log-based CDC reads a log the database already writes instead of querying your tables again and again. In PostgreSQL, for example, <a href="https://www.postgresql.org/docs/current/logicaldecoding-explanation.html" target="_blank" rel="noopener noreferrer" class="">logical decoding works by decoding the write-ahead log</a> (the file where the database records its changes) into a stream that outside programs can read.</p>
<p>Confluent's page says log-based CDC <a href="https://www.confluent.io/learn/change-data-capture/" target="_blank" rel="noopener noreferrer" class="">"doesn't impose computational overhead on source databases"</a>. That is vendor wording that we have not tested, and the same page notes that log formats are not standardized.</p>
<p>It says the other common method, timestamp-based CDC, can only process soft deletes and requires changes to the existing database schema.</p>
<p>The source still has chores, though. In PostgreSQL, a replication slot (a bookmark that tracks a change reader's place) <a href="https://www.postgresql.org/docs/current/logicaldecoding-explanation.html" target="_blank" rel="noopener noreferrer" class="">prevents removal of the log files it needs even when no connection is using it</a>. The docs say this consumes storage and, in extreme cases, could shut the database down, so a slot that is no longer needed should be dropped.</p>
<p>The docs name a place to look: the <a href="https://www.postgresql.org/docs/current/view-pg-replication-slots.html" target="_blank" rel="noopener noreferrer" class=""><code>pg_replication_slots</code> view</a> has a <code>wal_status</code> column. There, "extended" means the log has grown past <code>max_wal_size</code> but is still being kept. "Lost" means the slot is no longer usable.</p>
<p><strong>ETL and ELT</strong> differ in where the reshaping happens. On the ELT side, IBM says it has <a href="https://www.ibm.com/think/topics/etl" target="_blank" rel="noopener noreferrer" class="">a lower upfront cost, but unpredictable data volumes can cause unexpected costs later</a>. IBM adds that masking personal data in transit before loading is an ETL strength, and it still calls ETL a popular choice.</p>
<p><strong>Reverse ETL</strong> simply runs the other way. Fivetran's docs describe its Activations product as managed reverse ETL pipelines that deliver warehouse data into business tools. "Managed" is Fivetran's word, and Activations rows are billed on the same monthly-active-rows meter, per its usage-based pricing docs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-choose-four-questions-not-one">How to choose: four questions, not one<a href="https://olake.io/learn/what-is-a-data-pipeline/#how-to-choose-four-questions-not-one" class="hash-link" aria-label="Direct link to How to choose: four questions, not one" title="Direct link to How to choose: four questions, not one" translate="no">​</a></h2>
<p>The six labels above answer different questions, so freshness alone can't pick a row. Split the choice into four parts instead.</p>
<ul>
<li class=""><strong>How old can the data be?</strong> Hours or a day, minutes, or seconds (batch or streaming).</li>
<li class=""><strong>How do we find what changed?</strong> Copy whole tables, read timestamps, or read the database log (change data capture).</li>
<li class=""><strong>Where does the reshaping happen?</strong> Before loading or after loading (ETL or ELT).</li>
<li class=""><strong>Which way does the data flow?</strong> Into the warehouse, or back out to business tools (reverse ETL).</li>
</ul>
<p>Real designs combine the answers. For example, change capture can copy database changes into storage as they happen, and a scheduled job can build the reports from that data afterward. That one design mixes a change-log method, the ELT order and a batch-style schedule.</p>
<p><img decoding="async" loading="lazy" src="https://olake.io/img/blog/2026/10/what-is-a-data-pipeline-which-fits.webp" alt="Pipeline type chosen by freshness: nightly batch for reports, frequent syncs for dashboards, streaming for events in seconds" width="1600" height="1020" class="img_ev3q"></p>
<p>The diagram covers only the first question, timing. Start there, because you shouldn't pay for seconds when a report is read once a day.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-worked-example-an-online-shops-orders">A worked example: an online shop's orders<a href="https://olake.io/learn/what-is-a-data-pipeline/#a-worked-example-an-online-shops-orders" class="hash-link" aria-label="Direct link to A worked example: an online shop's orders" title="Direct link to A worked example: an online shop's orders" translate="no">​</a></h2>
<p>This example is an illustration with invented rows, not a real customer and not a test. Picture a small shop that keeps orders in a Postgres database, where the owner wants a daily sales report. Here's each stage, plus the one thing most likely to go wrong there.</p>
<table><thead><tr><th>Stage</th><th>What happens</th><th>What can go wrong</th></tr></thead><tbody><tr><td>Source</td><td>Orders sit in a Postgres table</td><td>Reading it too often slows the shop's own site</td></tr><tr><td>Ingestion</td><td>A tool copies new and changed orders every hour</td><td>A cancelled order is deleted at the source but never reaches the report</td></tr><tr><td>Transform (optional step)</td><td>A SQL query adds up sales per day and per product</td><td>A renamed column breaks the query overnight</td></tr><tr><td>Destination</td><td>A warehouse table feeds a dashboard</td><td>Two runs overlap and the same order is counted twice</td></tr><tr><td>Running it</td><td>A scheduler starts each step in order</td><td>A step fails at 3 a.m. and nobody is told</td></tr></tbody></table>
<p>The copy step ends when rows land in the warehouse, and the SQL query that adds up sales is the next step. Here are three invented orders to show the delete problem from the second row.</p>
<table><thead><tr><th>Order</th><th>What happens in the shop at 10 a.m.</th><th>Copy that reads timestamps only</th><th>Copy that reads the database log</th></tr></thead><tbody><tr><td>1001</td><td>Nothing</td><td>Unchanged</td><td>Unchanged</td></tr><tr><td>1002</td><td>Deleted after a cancellation</td><td>Still in the report</td><td>Removed from the report</td></tr><tr><td>1003</td><td>Status changes from Paid to Shipped</td><td>Updated, if the table keeps a reliable last-modified timestamp</td><td>Updated</td></tr></tbody></table>
<p>That gap is why the CDC type exists. A hard delete removes the row, and per Confluent, timestamp-based capture can only process soft deletes, so a scan has nothing to find.</p>
<p>A script with no alerts and no retries may still move data, but it isn't yet a production-ready pipeline.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="which-tools-do-which-job">Which tools do which job<a href="https://olake.io/learn/what-is-a-data-pipeline/#which-tools-do-which-job" class="hash-link" aria-label="Direct link to Which tools do which job" title="Direct link to Which tools do which job" translate="no">​</a></h2>
<p>A pipeline is a design, and tools are the parts you build it from. Each tool below does one slice, and most teams end up needing more than one.</p>
<table><thead><tr><th>Job</th><th>Example tool</th><th>Fits when</th><th>Named limit</th></tr></thead><tbody><tr><td>Schedule and order the steps</td><td>Apache Airflow</td><td>You want steps written as code, with retries and a clear start and end</td><td>Its docs call it a platform for <a href="https://airflow.apache.org/docs/apache-airflow/stable/index.html" target="_blank" rel="noopener noreferrer" class="">orchestrating batch workflows</a>, and you write Python</td></tr><tr><td>Reshape data in the warehouse</td><td>dbt</td><td>Your data is already in the warehouse and you work in SQL</td><td>Its docs say it <a href="https://docs.getdbt.com/docs/introduction" target="_blank" rel="noopener noreferrer" class="">works alongside your ingestion tools</a> to transform data, so another tool must load the data</td></tr><tr><td>Carry streams of events</td><td>Apache Kafka</td><td>Many systems must read the same events as they happen</td><td>It is <a href="https://kafka.apache.org/intro" target="_blank" rel="noopener noreferrer" class="">an event streaming platform</a> that you run or rent. It moves events, and getting them in and out of databases takes connectors you set up</td></tr><tr><td>Copy data on a vendor-run schedule</td><td>Fivetran</td><td>You want a vendor to run the loading</td><td>Database connectors sync <a href="https://fivetran.com/docs/connectors/databases" target="_blank" rel="noopener noreferrer" class="">every 15 minutes by default</a>. That schedule is Fivetran's default, not a freshness guarantee, because sync time, failures and later steps add delay</td></tr><tr><td>Copy data with self-run code</td><td>Airbyte (self-managed Core), Debezium</td><td>You want to run the software yourself and see the code</td><td>You run it yourself, so servers and fixing it are yours</td></tr></tbody></table>
<p>Fivetran and dbt are now one company, because Fivetran <a href="https://www.fivetran.com/press/fivetran-dbt-labs-complete-merger-to-create-the-data-infrastructure-for-trusted-ai-agents" target="_blank" rel="noopener noreferrer" class="">announced the completion of its merger with dbt Labs on June 1, 2026</a>. Check each vendor's pages for any change to how they're sold.</p>
<p>Before you rely on any vendor's freshness or reliability claim, ask for the worst-case delay (not the default schedule), how failed syncs and deleted rows are handled, and what exactly the bill counts.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-goes-wrong-and-how-to-guard-against-it">What goes wrong, and how to guard against it<a href="https://olake.io/learn/what-is-a-data-pipeline/#what-goes-wrong-and-how-to-guard-against-it" class="hash-link" aria-label="Direct link to What goes wrong, and how to guard against it" title="Direct link to What goes wrong, and how to guard against it" translate="no">​</a></h2>
<p>Most failures are boring and predictable, and each one maps to a row of the example above.</p>
<ul>
<li class=""><strong>Stale data.</strong> A report is only as fresh as the last successful run plus the time the later steps take. Fivetran's docs say a failed sync is retried after the update interval or one hour, whichever is shorter, so a failure can add that wait.</li>
<li class=""><strong>Missing deletes.</strong> Methods that look only for new or changed rows can miss rows that were removed. Reading the database log is one way around it, with the setup cost described above.</li>
<li class=""><strong>Duplicates after a crash.</strong> PostgreSQL says that after a crash a slot might return to an earlier position, so <a href="https://www.postgresql.org/docs/current/logicaldecoding-explanation.html" target="_blank" rel="noopener noreferrer" class="">recent changes are sent again</a>. The receiving side must be able to handle the same message twice.</li>
<li class=""><strong>Duplicates after a rerun.</strong> The Airflow docs say a retried task <a href="https://airflow.apache.org/docs/apache-airflow/stable/best-practices.html" target="_blank" rel="noopener noreferrer" class="">should produce the same outcome on every re-run</a>. The word for that is idempotent, which just means safe to run twice.</li>
<li class=""><strong>Changed columns.</strong> If the source renames or drops a column, the steps after it can fail, and nobody notices without an alert.</li>
<li class=""><strong>Cost surprises.</strong> Billing meters count rows, events or gigabytes, and each rises differently.</li>
</ul>
<p>Here is the rerun case with invented rows, as an illustration and not a test. Say a run that loads order 1003 (a 20-dollar sale) fails halfway and the scheduler runs it again.</p>
<table><thead><tr><th>Write style</th><th>After the first run</th><th>After the retry</th></tr></thead><tbody><tr><td>Blind insert</td><td>Order 1003 appears once</td><td>Order 1003 appears twice, so the day's sales are counted double</td></tr><tr><td>Upsert on the order number</td><td>Order 1003 appears once</td><td>Order 1003 still appears once</td></tr></tbody></table>
<p>The Airflow page says not to add rows blindly on a rerun, because that can create duplicates. Use an upsert (update the row if it exists, add it if not), which needs a column that identifies each row, here the order number.</p>
<p>That is one guard, not the whole answer, because a replayed old change must not overwrite a newer one. For scheduled batch tasks, the same page also says to read and write one named slice of data, such as one day, rather than "the latest data."</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="build-it-yourself-or-buy-a-tool">Build it yourself or buy a tool?<a href="https://olake.io/learn/what-is-a-data-pipeline/#build-it-yourself-or-buy-a-tool" class="hash-link" aria-label="Direct link to Build it yourself or buy a tool?" title="Direct link to Build it yourself or buy a tool?" translate="no">​</a></h2>
<p>Match your situation to a path below, then check the limit before you commit.</p>
<table><thead><tr><th>Your situation</th><th>Likely path</th><th>Why</th><th>Watch for</th></tr></thead><tbody><tr><td>One source, one daily report</td><td>A short script plus a scheduler</td><td>Few moving parts</td><td>You own every failure</td></tr><tr><td>Many apps, few engineers</td><td>A hosted loader such as Fivetran</td><td>A vendor runs the loading</td><td>Fivetran's docs bill by monthly active rows per connection, and its pricing page does not print the per-row rates</td></tr><tr><td>Engineers who want control</td><td>Open-source loaders and a scheduler</td><td>You see and change the code</td><td>You run and fix it yourself</td></tr><tr><td>Changes needed within minutes</td><td>CDC from your database, such as Debezium</td><td>Reads the change log</td><td>Database setup and log retention</td></tr><tr><td>Reports can be a day old</td><td>Plain batch</td><td>Fewest moving parts</td><td>Stale by design</td></tr></tbody></table>
<section class="root_PuUS" aria-labelledby="_R_flqfdbih_-h"><header><h3 id="_R_flqfdbih_-h" class="title_QNC9" tabindex="-1">Test your data pipeline basics</h3></header><div class="progress_EyIk" role="progressbar" aria-valuemin="1" aria-valuemax="5" aria-valuenow="1" aria-label="Quiz progress"><span style="width:0%"></span></div><p class="count_OugS">Question <!-- -->1<!-- --> of <!-- -->5</p><p id="_R_flqfdbih_-q" class="question_IKMS">Does a data pipeline have to reshape the data it moves?</p><div role="radiogroup" aria-labelledby="_R_flqfdbih_-q" class="options_xbjx"><button type="button" role="radio" aria-checked="false" tabindex="0" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">A</span><span class="optLabel_qDTb">Yes, every pipeline must clean and reformat its data</span></button><button type="button" role="radio" aria-checked="false" tabindex="-1" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">B</span><span class="optLabel_qDTb">No, it may simply move data from one system to another</span></button><button type="button" role="radio" aria-checked="false" tabindex="-1" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">C</span><span class="optLabel_qDTb">Only when it runs all day without stopping</span></button><button type="button" role="radio" aria-checked="false" tabindex="-1" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">D</span><span class="optLabel_qDTb">Only when the data ends up in cheap file storage</span></button></div><div class="actions_XZHX"><button type="button" class="primary_KVNI" disabled="">Next</button></div></section>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="frequently-asked-questions">Frequently asked questions<a href="https://olake.io/learn/what-is-a-data-pipeline/#frequently-asked-questions" class="hash-link" aria-label="Direct link to Frequently asked questions" title="Direct link to Frequently asked questions" translate="no">​</a></h2>
<div class="olake-faq"><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q1. What is a data pipeline in simple words?</span></summary><div class="olake-faq__answer">It's an automated path that moves data from where it's created to where it's used, such as from a shop's database to a report. AWS describes it as a series of processing steps that prepare data for analysis.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q2. Is a data pipeline the same as ETL?</span></summary><div class="olake-faq__answer">Nope. ETL is one kind of data pipeline, where data is reshaped before loading. IBM says a data pipeline may simply move data from one system to another without any transformation.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q3. What are the main types of data pipeline?</span></summary><div class="olake-faq__answer">The most common split is batch, which runs at set times, and streaming, which runs continuously. The other labels answer different questions: where data is reshaped (ETL or ELT), how changes are found (change data capture) and which way data flows (reverse ETL).</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q4. What are the parts of a data pipeline?</span></summary><div class="olake-faq__answer">IBM names three stages: ingestion, transformation (optional, since a pipeline may only move data) and storage. In practice you also need scheduling, retries and monitoring, because AWS says a good pipeline must keep working when parts fail.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q5. What is the difference between a data pipeline and a workflow scheduler like Airflow?</span></summary><div class="olake-faq__answer">The pipeline is the path your data takes. Airflow is a tool that starts and orders the steps along that path, and its docs describe it as a platform for orchestrating batch workflows.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q6. Do I need real-time streaming?</span></summary><div class="olake-faq__answer">Only if someone acts on the data within seconds. If it feeds a daily report, a batch pipeline is simpler. Fivetran's database connectors sync every 15 minutes by default, but sync time, failures and later steps add to the age of the data.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q7. What makes a data pipeline reliable?</span></summary><div class="olake-faq__answer">Being safe to rerun. Airflow's docs say a retried task should produce the same outcome each time, and they advise an upsert instead of a plain insert so reruns don't add duplicate rows. Then add alerts, so a person hears about a failed run.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q8. Should I build a pipeline myself or use a tool?</span></summary><div class="olake-faq__answer">For one source and one report, a script and a scheduler can be enough. With many sources and few engineers, a managed loader saves time but adds a bill, and open-source tools give you control but need people to run them.</div></details></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://olake.io/learn/what-is-a-data-pipeline/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Start with how old the data can be. Then add a scheduler, safe reruns and alerts, and check each vendor page before you spend money.</p>
<aside class="not-prose my-10 rounded-[16px] border border-solid border-olake-line bg-olake-surface p-[24px] lg:p-[32px]"><p class="m-0 text-[22px] leading-[1.2] tracking-[-0.01em] text-olake-ink lg:text-[26px]">OLake Go</p><p class="m-0 mt-[10px] max-w-[620px] text-[15px] leading-[1.6] text-olake-text-2">Replicate databases, Kafka, and S3 into Apache Iceberg with OLake Go, an open source EL engine built for Iceberg from the ground up.</p><div class="mt-[20px] flex flex-wrap gap-[10px]"><a href="https://olake.io/contact/" class="lk-press inline-flex h-[38px] items-center justify-center gap-[8px] rounded-[8px] border border-solid px-[16px] text-[14px] no-underline transition-colors border-olake-blue-ring bg-olake-blue text-olake-on-blue! hover:border-olake-blue-hover hover:bg-olake-blue-hover hover:text-white!"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="13" width="13" xmlns="http://www.w3.org/2000/svg"><path d="M224,104a8,8,0,0,1-16,0V59.32l-66.33,66.34a8,8,0,0,1-11.32-11.32L196.68,48H152a8,8,0,0,1,0-16h64a8,8,0,0,1,8,8Zm-40,24a8,8,0,0,0-8,8v72H48V80h72a8,8,0,0,0,0-16H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V136A8,8,0,0,0,184,128Z"></path></svg>Signup</a><a href="https://olake.io/slack/" target="_blank" rel="noopener noreferrer" class="lk-press inline-flex h-[38px] items-center justify-center gap-[8px] rounded-[8px] border border-solid px-[16px] text-[14px] no-underline transition-colors border-olake-btn-border bg-olake-surface text-olake-btn-secondary! hover:bg-olake-surface-alt hover:text-olake-ink!"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="15" width="15" xmlns="http://www.w3.org/2000/svg"><path d="M221.13,128A32,32,0,0,0,184,76.31V56a32,32,0,0,0-56-21.13A32,32,0,0,0,76.31,72H56a32,32,0,0,0-21.13,56A32,32,0,0,0,72,179.69V200a32,32,0,0,0,56,21.13A32,32,0,0,0,179.69,184H200a32,32,0,0,0,21.13-56ZM72,152a16,16,0,1,1-16-16H72Zm48,48a16,16,0,0,1-32,0V152a16,16,0,0,1,16-16h16Zm0-80H56a16,16,0,0,1,0-32h48a16,16,0,0,1,16,16Zm0-48H104a16,16,0,1,1,16-16Zm16-16a16,16,0,0,1,32,0v48a16,16,0,0,1-16,16H136Zm16,160a16,16,0,0,1-16-16V184h16a16,16,0,0,1,0,32Zm48-48H152a16,16,0,0,1-16-16V136h64a16,16,0,0,1,0,32Zm0-48H184V104a16,16,0,1,1,16,16Z"></path></svg>Join Slack</a><a href="https://github.com/datazip-inc/olake" target="_blank" rel="noopener noreferrer" class="lk-press inline-flex h-[38px] items-center justify-center gap-[8px] rounded-[8px] border border-solid px-[16px] text-[14px] no-underline transition-colors border-olake-btn-border bg-olake-surface text-olake-btn-secondary! hover:bg-olake-surface-alt hover:text-olake-ink!"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="15" width="15" xmlns="http://www.w3.org/2000/svg"><path d="M208.31,75.68A59.78,59.78,0,0,0,202.93,28,8,8,0,0,0,196,24a59.75,59.75,0,0,0-48,24H124A59.75,59.75,0,0,0,76,24a8,8,0,0,0-6.93,4,59.78,59.78,0,0,0-5.38,47.68A58.14,58.14,0,0,0,56,104v8a56.06,56.06,0,0,0,48.44,55.47A39.8,39.8,0,0,0,96,192v8H72a24,24,0,0,1-24-24A40,40,0,0,0,8,136a8,8,0,0,0,0,16,24,24,0,0,1,24,24,40,40,0,0,0,40,40H96v16a8,8,0,0,0,16,0V192a24,24,0,0,1,48,0v40a8,8,0,0,0,16,0V192a39.8,39.8,0,0,0-8.44-24.53A56.06,56.06,0,0,0,216,112v-8A58.14,58.14,0,0,0,208.31,75.68ZM200,112a40,40,0,0,1-40,40H112a40,40,0,0,1-40-40v-8a41.74,41.74,0,0,1,6.9-22.48A8,8,0,0,0,80,73.83a43.81,43.81,0,0,1,.79-33.58,43.88,43.88,0,0,1,32.32,20.06A8,8,0,0,0,119.82,64h32.35a8,8,0,0,0,6.74-3.69,43.87,43.87,0,0,1,32.32-20.06A43.81,43.81,0,0,1,192,73.83a8.09,8.09,0,0,0,1,7.65A41.72,41.72,0,0,1,200,104Z"></path></svg>Explore OLake GitHub</a></div><p class="m-0 mt-[16px] text-[13px] text-olake-muted">Contact us at <strong class="font-medium text-olake-text-2">hello@olake.io</strong></p></aside>]]></content:encoded>
            <author>hello@olake.io (Priyansh Khodiyar)</author>
            <category>Data Pipeline Tools</category>
            <category>ETL</category>
            <category>Data Ingestion</category>
        </item>
        <item>
            <title><![CDATA[ETL Pipelines: What They Are and How They Work (2026)]]></title>
            <link>https://olake.io/learn/etl-pipelines/</link>
            <guid>https://olake.io/learn/etl-pipelines/</guid>
            <pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[ETL pipelines explained in plain words: the three steps, a worked example, where they break, ETL vs ELT, and when to pick each. Sourced and dated.]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="eager" src="https://olake.io/img/blog/cover/etl-pipelines-cover.webp" alt="ETL pipeline cover showing sources flowing through a transform step into a warehouse or data lake" width="1920" height="1080" fetchpriority="high" class="img_ev3q"></p>
<p>ETL (extract, transform, load) pipelines are easy to describe and easy to get wrong. An ETL pipeline is an automated process that extracts data from your source systems, transforms it (cleans and reshapes it), and loads it into a destination such as a data warehouse or data lake. In ELT (extract, load, transform) the same reshaping happens after the data lands instead of before.</p>
<p>Facts below come from linked vendor, project and reference pages, read on October 1, 2026. We did not build or run a pipeline for this guide, and the one worked example uses invented rows. Several of the pages are from companies that sell cloud services or data tools, so their claims are reported as their claims and we have not tested them.</p>
<section class="olake-tldr" aria-label="Key takeaways"><p class="olake-tldr__label"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="M215.79,118.17a8,8,0,0,0-5-5.66L153.18,90.9l14.66-73.33a8,8,0,0,0-13.69-7l-112,120a8,8,0,0,0,3,13l57.63,21.61L88.16,238.43a8,8,0,0,0,13.69,7l112-120A8,8,0,0,0,215.79,118.17ZM109.37,214l10.47-52.38a8,8,0,0,0-5-9.06L62,132.71l84.62-90.66L136.16,94.43a8,8,0,0,0,5,9.06l52.8,19.8Z"></path></svg><span>Key takeaways</span></p><div class="olake-tldr__body"><ul>
<li class=""><strong>ETL</strong> stands for extract, transform, load. IBM <a href="https://www.ibm.com/think/topics/etl" target="_blank" rel="noopener noreferrer" class="">describes it</a> as a data integration process that combines, cleans and organizes data from several sources and loads it into a warehouse or other target.</li>
<li class="">An ETL pipeline is the automated, repeatable version of that process. It's one kind of data pipeline, not the only kind.</li>
<li class="">The three steps don't always run in strict order. <a href="https://learn.microsoft.com/en-us/azure/architecture/data-guide/relational-data/etl" target="_blank" rel="noopener noreferrer" class="">Microsoft says</a> they often run in parallel to save time.</li>
<li class="">Our read: pipeline trouble often comes from reruns and changes, not from the three steps themselves. A retried load can write the same rows twice unless it's built to be safe to repeat.</li>
<li class="">ETL isn't dead. Microsoft and AWS list cases where each of ETL and ELT fits.</li>
</ul></div></section>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-an-etl-pipeline-in-plain-words">What is an ETL pipeline, in plain words?<a href="https://olake.io/learn/etl-pipelines/#what-is-an-etl-pipeline-in-plain-words" class="hash-link" aria-label="Direct link to What is an ETL pipeline, in plain words?" title="Direct link to What is an ETL pipeline, in plain words?" translate="no">​</a></h2>
<p>Picture a restaurant chain that wants one report on yesterday's sales. The orders sit in a database, the refunds sit in a spreadsheet, and the delivery sales come from an app. Somebody has to collect all three, fix the mismatches, and put the result in one place.</p>
<p>An ETL pipeline automates that job, so nobody repeats it by hand each morning.</p>
<p>First it extracts (copies) the data from each source. Then it transforms (cleans, reshapes and combines) that data. Last, it loads (writes) the result into a destination where people can query it.</p>
<p><a href="https://aws.amazon.com/what-is/etl/" target="_blank" rel="noopener noreferrer" class="">AWS defines ETL</a> as combining data from multiple sources into a large, central repository called a data warehouse, using business rules to clean and organize it first. Other sources widen the target a bit. <a href="https://cloud.google.com/learn/what-is-etl" target="_blank" rel="noopener noreferrer" class="">Google Cloud</a> also names a database, a data store or a data lake as destinations.</p>
<p>Two ideas hide inside the word "pipeline". The process is automated, so it runs on a schedule or a trigger. And it's repeatable, so the same steps run again and again on fresh data.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-three-steps-of-an-etl-pipeline">The three steps of an ETL pipeline<a href="https://olake.io/learn/etl-pipelines/#the-three-steps-of-an-etl-pipeline" class="hash-link" aria-label="Direct link to The three steps of an ETL pipeline" title="Direct link to The three steps of an ETL pipeline" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="extract-copy-the-data-out">Extract: copy the data out<a href="https://olake.io/learn/etl-pipelines/#extract-copy-the-data-out" class="hash-link" aria-label="Direct link to Extract: copy the data out" title="Direct link to Extract: copy the data out" translate="no">​</a></h3>
<p>Extraction pulls records out of the source. Sources can be databases, files, web services (APIs) and event streams. Wikipedia's <a href="https://en.wikipedia.org/wiki/Extract,_transform,_load" target="_blank" rel="noopener noreferrer" class="">ETL article</a> adds that extraction usually includes a validation check, and that rows which fail the rules should ideally be rejected and reported back so someone can correct them.</p>
<p>The hard part isn't copying. It's deciding what to copy each time.</p>
<p>One common design is a first run that copies everything, which is called a full load. Later runs then copy only what's new or changed, which is called an incremental load. We'll get to how that works in a minute.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="transform-clean-and-reshape">Transform: clean and reshape<a href="https://olake.io/learn/etl-pipelines/#transform-clean-and-reshape" class="hash-link" aria-label="Direct link to Transform: clean and reshape" title="Direct link to Transform: clean and reshape" translate="no">​</a></h3>
<p>This is the step that makes ETL, well, ETL. Microsoft lists the usual operations as filtering, sorting, aggregating, joining, cleaning, deduplicating and validating data. In its description, the transformation applies business rules, using a specialised engine, often with staging tables that temporarily hold the data while it is processed.</p>
<p>Google Cloud says extracted data is first loaded into a staging area, then cleaned and put into a common format, which typically means removing duplicate, incomplete or obviously wrong records.</p>
<p>International Business Machines (IBM) adds one reason people still pick ETL. It says ETL can mask sensitive data while it's still in transit, before it reaches the destination. That matters if you'd rather not have private columns land anywhere they shouldn't, but it is IBM's claim and we did not test it.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="load-write-it-to-the-destination">Load: write it to the destination<a href="https://olake.io/learn/etl-pipelines/#load-write-it-to-the-destination" class="hash-link" aria-label="Direct link to Load: write it to the destination" title="Direct link to Load: write it to the destination" translate="no">​</a></h3>
<p>Loading writes the prepared data to its final home. That can be a data warehouse (a database built for reports and analysis), a data lake (cheap storage for files in many formats) or a regular database. <a href="https://estuary.dev/blog/what-is-an-etl-pipeline/" target="_blank" rel="noopener noreferrer" class="">Estuary's guide</a> notes that loads can be full (replace everything) or incremental (add or update only what changed).</p>
<p>Microsoft says the three phases often overlap, so don't picture a strict assembly line. While data is still being extracted, a transformation can already work on what has arrived. Loading can start on prepared data too, instead of waiting for extraction to finish.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-surrounds-the-three-steps">What surrounds the three steps<a href="https://olake.io/learn/etl-pipelines/#what-surrounds-the-three-steps" class="hash-link" aria-label="Direct link to What surrounds the three steps" title="Direct link to What surrounds the three steps" translate="no">​</a></h2>
<p>A daily pipeline also needs something to schedule it and something to watch it.</p>
<p>Microsoft splits the scheduling side into two ideas. Control flow decides the order of tasks, and a task can't start until the one before it has finished with a success, failure or completion result. Data flow is the movement and reshaping of the data inside one task.</p>
<p>On the tooling side, <a href="https://estuary.dev/blog/what-is-an-etl-pipeline/" target="_blank" rel="noopener noreferrer" class="">Estuary's guide</a> names Apache Airflow, Dagster and Prefect as orchestrators, the programs that run the steps on a schedule. <a href="https://stripe.com/resources/more/etl-pipeline" target="_blank" rel="noopener noreferrer" class="">Stripe's guide</a> says to monitor job runtimes, row counts, error rates and freshness, and to set alerts for failures.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-worked-illustration-with-invented-rows">A worked illustration with invented rows<a href="https://olake.io/learn/etl-pipelines/#a-worked-illustration-with-invented-rows" class="hash-link" aria-label="Direct link to A worked illustration with invented rows" title="Direct link to A worked illustration with invented rows" translate="no">​</a></h2>
<p>This example is made up. The orders, amounts and dates are invented, and nobody ran it as a test. It only shows how the three steps and the counts fit together.</p>
<p>Say a shop keeps orders in a table called <code>raw_orders</code>. Each row has an order number, an amount in cents, a status, a customer email and a last-updated time. The goal is a clean <code>sales</code> table the finance team can trust.</p>
<p>An earlier run already loaded order 090 into it, so <code>sales</code> starts with one row.</p>
<table><thead><tr><th>order_id</th><th>amount_cents</th><th>status</th><th>email</th><th>updated_at</th></tr></thead><tbody><tr><td>090</td><td>3000</td><td>paid</td><td><a href="mailto:old@example.com" target="_blank" rel="noopener noreferrer" class="">old@example.com</a></td><td>2026-09-12 09:00</td></tr><tr><td>101</td><td>2599</td><td>paid</td><td><a href="mailto:ana@example.com" target="_blank" rel="noopener noreferrer" class="">ana@example.com</a></td><td>2026-09-30 10:02</td></tr><tr><td>102</td><td>1000</td><td>test</td><td><a href="mailto:qa@example.com" target="_blank" rel="noopener noreferrer" class="">qa@example.com</a></td><td>2026-09-30 11:15</td></tr><tr><td>103</td><td>4500</td><td>paid</td><td><a href="mailto:raj@example.com" target="_blank" rel="noopener noreferrer" class="">raj@example.com</a></td><td>2026-09-30 18:40</td></tr></tbody></table>
<p>Now say the last run finished at midnight on September 30. The pipeline remembers that time, and that remembered point is called a watermark. Here's each step.</p>
<p><strong>Extract.</strong> Read only the rows updated after the watermark. That skips order 090, which an earlier run already handled, so three rows are extracted: 101, 102 and 103.</p>
<p><strong>Transform.</strong> Reject the test order (102), turn cents into a dollar amount, and leave the email column behind so it never reaches the destination. One row is rejected and two pass.</p>
<p><strong>Load.</strong> Write the two passing rows into <code>sales</code> with an upsert. That's just "insert this row, or update it if the order number already exists".</p>
<table><thead><tr><th>Count</th><th>Rows</th><th>Which ones</th></tr></thead><tbody><tr><td>Extracted</td><td>3</td><td>101, 102, 103</td></tr><tr><td>Rejected by the transform</td><td>1</td><td>102 (test order)</td></tr><tr><td>Loaded into <code>sales</code></td><td>2</td><td>101 at 25.99, 103 at 45.00</td></tr></tbody></table>
<p>After the run, <code>sales</code> holds three rows: the old 090 plus the new 101 and 103.</p>
<p>Now run the same window a second time. Because the load is an upsert, 101 and 103 are updated in place and <code>sales</code> still holds the same three rows. A plain insert could add them again.</p>
<p>That repeat-safety is the idea behind the "where pipelines break" section. Two gaps show up even in this tiny case.</p>
<p>First, a filter only decides what gets loaded. If order 101 is later changed to a test order, the next run extracts it and rejects it, so the old 101 row stays in <code>sales</code>. Removing it would take a separate delete or flag step.</p>
<p>Second, think about when the remembered time moves forward. If it jumps to the end of the day before the load finishes and the load then fails, 101 and 103 are skipped on the next run. So the sensible order is to move it only after the load succeeds.</p>
<p>Both points, and the counts above, are our reasoning from this invented example, not claims from a source. The counts rule is also specific to it: each row comes out once or is rejected. Joins and aggregations change row counts in other ways.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-pipelines-pick-up-changes">How pipelines pick up changes<a href="https://olake.io/learn/etl-pipelines/#how-pipelines-pick-up-changes" class="hash-link" aria-label="Direct link to How pipelines pick up changes" title="Direct link to How pipelines pick up changes" translate="no">​</a></h2>
<p>That watermark is the simplest way to run incremental loads. Microsoft's <a href="https://learn.microsoft.com/en-us/azure/data-factory/tutorial-incremental-copy-overview" target="_blank" rel="noopener noreferrer" class="">Azure Data Factory docs</a> describe a watermark as a column that holds the last updated time or an incrementing key. A delta load then copies the data between an old watermark and a new one.</p>
<p>Here's the catch: a watermark needs a column that reliably moves forward.</p>
<p>If a table has no such column, or someone forgets to update it, rows get missed. The query only sees rows that still exist, so it can't show you a row that was deleted. Our read: when deletes matter, the pipeline needs a different method.</p>
<p>The same Microsoft page lists other methods. Change Tracking is a lightweight SQL Server feature that identifies inserted, updated or deleted data. For files, it describes filtering by last-modified date, and warns that scanning huge numbers of files to copy only a few is still slow.</p>
<p>There's also a fuller approach that reads the database's own change log.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="three-ways-to-build-one-and-what-each-costs-you">Three ways to build one (and what each costs you)<a href="https://olake.io/learn/etl-pipelines/#three-ways-to-build-one-and-what-each-costs-you" class="hash-link" aria-label="Direct link to Three ways to build one (and what each costs you)" title="Direct link to Three ways to build one (and what each costs you)" translate="no">​</a></h2>
<p>Estuary's guide names three common routes. One caveat: Estuary sells a pipeline product, so treat its framing as one vendor's view.</p>
<table><thead><tr><th>Route</th><th>What it looks like</th><th>Strength</th><th>The catch</th></tr></thead><tbody><tr><td>Code you write</td><td>Python with libraries such as pandas or SQLAlchemy, run by an orchestrator such as Airflow</td><td>Full control over every rule</td><td>You own retries, reruns and alerts yourself</td></tr><tr><td>Managed platform</td><td>Built-in connectors, scheduling and schema change handling</td><td>Estuary says it is faster to stand up and has less to maintain (not tested by us)</td><td>You depend on what its connectors support, and you pay the vendor's price, so ask for both in writing</td></tr><tr><td>Warehouse SQL</td><td>Raw data loaded first, then dbt-style models inside the warehouse</td><td>Raw data stays available, and analysts can edit the models</td><td>This is ELT, not ETL, and it needs a strong destination</td></tr></tbody></table>
<p>Estuary says production needs four things beyond the three steps: a staging area, a scheduler, incremental loads and validation. Its validation list: schema checks, null thresholds and row-count reconciliation, which means comparing how many rows left the source with how many arrived.</p>
<p>A cheap check is a row-count comparison after each load. Our read: when each row either passes or is rejected, compare extracted against rejected plus loaded (3 = 1 + 2 in the illustration). Comparing source rows to loaded rows would raise a false alarm whenever the transform drops something on purpose.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-etl-pipelines-break-and-why-its-rarely-the-three-steps">Where ETL pipelines break (and why it's rarely the three steps)<a href="https://olake.io/learn/etl-pipelines/#where-etl-pipelines-break-and-why-its-rarely-the-three-steps" class="hash-link" aria-label="Direct link to Where ETL pipelines break (and why it's rarely the three steps)" title="Direct link to Where ETL pipelines break (and why it's rarely the three steps)" translate="no">​</a></h2>
<p>Our read of the sources below: trouble usually starts outside the three steps, in reruns, late data, changing sources and silent errors. Four of these are worth knowing before you build or buy.</p>
<p><strong>A rerun writes duplicates.</strong> Orchestrators retry failed tasks. That's their job, and it's also where the trouble starts.</p>
<p>The <a href="https://airflow.apache.org/docs/apache-airflow/stable/best-practices.html" target="_blank" rel="noopener noreferrer" class="">Apache Airflow best practices</a> say a task should produce the same outcome on every re-run. On top of that, they say you shouldn't use a plain insert during a re-run because it might lead to duplicate rows. The advice is to use an upsert instead.</p>
<p><img decoding="async" loading="lazy" src="https://olake.io/img/blog/2026/10/airflow-best-practices-idempotent.webp" alt="Apache Airflow best practices page, Creating a task section, with the INSERT, partition and now() re-run rules" width="1600" height="648" class="img_ev3q"></p>
<p><em>Apache Airflow best practices, "Creating a task", October 2026.</em></p>
<p>That page also says to read and write in a specific partition, and never to read "the latest available data" in a task. Someone may update the input between re-runs, and then you get different outputs. It also warns against using the current time (<code>now()</code>) inside a task for critical computation, since that gives a different result on each run.</p>
<p><img decoding="async" loading="lazy" src="https://olake.io/img/blog/2026/10/etl-pipelines-rerun.webp" alt="Diagram: a retried INSERT adds duplicate rows, while a retried UPSERT on one partition gives the same result" width="1600" height="720" class="img_ev3q"></p>
<p>A task that gives the same result when run twice is called idempotent (a fancy word for "safe to repeat"). Microsoft uses the same word and says to design parallel work around partition boundaries such as date, tenant or shard key, to avoid write conflicts and allow idempotent retries.</p>
<p><strong>Half-finished results.</strong> The Airflow page says to treat tasks like transactions in a database, so a task never leaves incomplete results behind. Its example: don't leave incomplete data in file or object storage at the end of a task. Nobody wants to find half a file at 9 a.m.</p>
<p><strong>Late or out-of-order data.</strong> For streaming pipelines, Microsoft recommends checkpointing for at-least-once processing and idempotent transformations to handle duplicates. It also recommends watermarking for late-arriving events and out-of-order processing, and dead letter queues (a holding place) for messages that can't be processed.</p>
<p>That streaming "watermarking" is a different idea from the remembered time in the worked illustration. The first deals with events that show up late. The second marks where the last batch stopped.</p>
<p><strong>Delay by design.</strong> Estuary says traditional batch processing is straightforward to implement but introduces delay by design. That suits a nightly report, less so fraud checks.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-people-use-etl-pipelines-for">What people use ETL pipelines for<a href="https://olake.io/learn/etl-pipelines/#what-people-use-etl-pipelines-for" class="hash-link" aria-label="Direct link to What people use ETL pipelines for" title="Direct link to What people use ETL pipelines for" translate="no">​</a></h2>
<p>Qlik lists data migration from legacy systems, centralizing data into one source of truth, enriching data by combining platforms, supporting privacy rules and preparing data sets for analytics. Stripe's guide adds examples built on joined data, such as marketing analytics that joins ad platforms, web data and customer records, and fraud detection that pulls together transaction, login and device data.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="etl-pipeline-vs-data-pipeline-not-the-same-thing">ETL pipeline vs data pipeline: not the same thing<a href="https://olake.io/learn/etl-pipelines/#etl-pipeline-vs-data-pipeline-not-the-same-thing" class="hash-link" aria-label="Direct link to ETL pipeline vs data pipeline: not the same thing" title="Direct link to ETL pipeline vs data pipeline: not the same thing" translate="no">​</a></h2>
<p>A data pipeline is the bigger idea: any automated movement of data from one place to another. <a href="https://www.ibm.com/think/topics/data-pipeline" target="_blank" rel="noopener noreferrer" class="">IBM lists four common types</a>: batch, streaming, data integration and cloud-native.</p>
<p>An ETL pipeline is a data pipeline that includes a transform step before loading. Not every data pipeline does that. <a href="https://www.qlik.com/us/etl/etl-pipeline" target="_blank" rel="noopener noreferrer" class="">Qlik</a> says a data pipeline may transform after loading (ELT) or not transform at all.</p>
<p><a href="https://www.informatica.com/resources/articles/what-is-etl-pipeline.html" target="_blank" rel="noopener noreferrer" class="">Informatica</a> says ETL pipelines run in batches while data pipelines work in real time. Google Cloud says streaming ETL pipelines now exist alongside batch ones, and IBM calls ETL with streaming technology "streaming ETL".</p>
<p>So batch versus real time is a choice you make. It's not what separates ETL from other pipelines.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="etl-vs-elt-which-order-fits-you">ETL vs ELT: which order fits you?<a href="https://olake.io/learn/etl-pipelines/#etl-vs-elt-which-order-fits-you" class="hash-link" aria-label="Direct link to ETL vs ELT: which order fits you?" title="Direct link to ETL vs ELT: which order fits you?" translate="no">​</a></h2>
<p>ELT means extract, load, transform. The only difference, per Microsoft, is where the transformation happens. In ELT it runs inside the destination, using that system's own processing power instead of a separate engine.</p>
<p>Microsoft's conditions are the clearest we found.</p>
<table><thead><tr><th>Choose ETL when</th><th>Choose ELT when</th></tr></thead><tbody><tr><td>You need to move heavy transformations off a constrained target system</td><td>The target is a modern warehouse or lakehouse with elastic compute</td></tr><tr><td>Complex business rules need a specialised transformation engine</td><td>You need to keep raw data for exploring or for future schema changes</td></tr><tr><td>Regulatory or compliance rules require curated staging audits before loading</td><td>The transformation benefits from the target's native capabilities</td></tr></tbody></table>
<p>Each side has limits. Microsoft says ELT only works well when the target is powerful enough to transform the data efficiently. IBM says ELT can lower upfront cost, but unpredictable data volumes can cause unexpected costs later, and unstructured data can take time to format inside the target.</p>
<p>AWS says in its ETL vs ELT comparison that the two may be used together for complex analytics that use multiple data formats from varied sources. One more term you'll hear: a lakehouse is a data lake that adds table features such as reliable updates, so it can serve as an ELT target.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="two-neighbours-reverse-etl-and-streaming">Two neighbours: reverse ETL and streaming<a href="https://olake.io/learn/etl-pipelines/#two-neighbours-reverse-etl-and-streaming" class="hash-link" aria-label="Direct link to Two neighbours: reverse ETL and streaming" title="Direct link to Two neighbours: reverse ETL and streaming" translate="no">​</a></h2>
<p>People often mix these two up with ETL. Microsoft describes reverse ETL as moving transformed, modeled data from analytical systems such as a warehouse back into operational tools such as a customer relationship management (CRM) system, a marketing tool or a support system. It still follows extract, transform and load, only in the other direction.</p>
<p>Microsoft contrasts real-time streaming with ETL and ELT, which it describes as operating on datasets in scheduled batches. Streaming instead processes data as it arrives, through a message broker or event hub and a stream processor. It suits cases where low latency is critical, such as fraud detection or live dashboards.</p>
<p>Some sources use the phrase "streaming ETL", so how often a pipeline runs is a separate question from where the transformation happens.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-which-should-you-pick">So which should you pick?<a href="https://olake.io/learn/etl-pipelines/#so-which-should-you-pick" class="hash-link" aria-label="Direct link to So which should you pick?" title="Direct link to So which should you pick?" translate="no">​</a></h2>
<table><thead><tr><th>Your situation</th><th>Likely fit</th><th>Why, and the catch</th></tr></thead><tbody><tr><td>Nightly finance report, small data, rules must be audited</td><td>ETL</td><td>Microsoft lists audit-before-load as an ETL case. The pipeline needs its own engine and care.</td></tr><tr><td>Cloud warehouse with plenty of compute, many analysts</td><td>ELT</td><td>Raw data stays available. IBM warns that cost can grow if volumes jump.</td></tr><tr><td>Need results as events happen</td><td>Streaming</td><td>Microsoft lists extra reliability work, such as checkpoints and idempotent design.</td></tr><tr><td>Pushing warehouse results into a CRM</td><td>Reverse ETL</td><td>Moves data the opposite way (Microsoft).</td></tr><tr><td>Table with no reliable change column</td><td>Full reload or change log</td><td>A watermark needs a change column and cannot see deletes.</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-checklist-before-you-trust-a-pipeline">A checklist before you trust a pipeline<a href="https://olake.io/learn/etl-pipelines/#a-checklist-before-you-trust-a-pipeline" class="hash-link" aria-label="Direct link to A checklist before you trust a pipeline" title="Direct link to A checklist before you trust a pipeline" translate="no">​</a></h2>
<p>Run these questions on a pipeline you've inherited, or on a tool you're about to buy. Each one maps to a failure described above.</p>
<ul>
<li class="">Does it copy everything once and then only changes, or work another way? How does it know what changed?</li>
<li class="">Can it see deletes, or only new and updated rows?</li>
<li class="">What happens if a run fails halfway? Can it be rerun without duplicates?</li>
<li class="">Where does raw data sit, and who can read it? Are sensitive columns masked before loading?</li>
<li class="">Who is alerted when a run fails or loads zero rows?</li>
<li class="">What does a late-arriving row do to yesterday's numbers?</li>
</ul>
<p>If a vendor can't answer these in its docs, the answer is "not published". Ask before you sign, and treat any latency, uptime, "no maintenance" or savings claim as unverified until you see it in the docs or in a test you ran.</p>
<p>For an alert rule, here is our read of the illustration above. Alert when a run fails, when extracted does not equal rejected plus loaded, or when a run loads zero rows on a day you expect changes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://olake.io/learn/etl-pipelines/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>An ETL pipeline is three steps wrapped in automation. What decides whether one is any good is how it finds changes, how it handles a failed run, and how fast someone learns that something broke.</p>
<p>Go with ETL when you need to reshape or mask data before it lands, or when audit rules ask for it. Pick ELT when your destination is strong and you want to keep the raw data around. Plenty of teams end up using both.</p>
<p>Last reviewed October 2026.</p>
<section class="root_PuUS" aria-labelledby="_R_nlqfdbih_-h"><header><h3 id="_R_nlqfdbih_-h" class="title_QNC9" tabindex="-1">Test your ETL pipeline basics</h3></header><div class="progress_EyIk" role="progressbar" aria-valuemin="1" aria-valuemax="5" aria-valuenow="1" aria-label="Quiz progress"><span style="width:0%"></span></div><p class="count_OugS">Question <!-- -->1<!-- --> of <!-- -->5</p><p id="_R_nlqfdbih_-q" class="question_IKMS">A restaurant chain keeps orders in a database, refunds in a spreadsheet and delivery sales in an app. What would an ETL pipeline do for them?</p><div role="radiogroup" aria-labelledby="_R_nlqfdbih_-q" class="options_xbjx"><button type="button" role="radio" aria-checked="false" tabindex="0" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">A</span><span class="optLabel_qDTb">Replace the three systems with one new app</span></button><button type="button" role="radio" aria-checked="false" tabindex="-1" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">B</span><span class="optLabel_qDTb">Collect, clean and combine the data into one place, without anyone doing it by hand</span></button><button type="button" role="radio" aria-checked="false" tabindex="-1" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">C</span><span class="optLabel_qDTb">Email the sales numbers to the manager each morning</span></button><button type="button" role="radio" aria-checked="false" tabindex="-1" class="option_bPD6"><span class="chip_dE9N" aria-hidden="true">D</span><span class="optLabel_qDTb">Back up each system separately in case of a crash</span></button></div><div class="actions_XZHX"><button type="button" class="primary_KVNI" disabled="">Next</button></div></section>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="faqs">FAQs<a href="https://olake.io/learn/etl-pipelines/#faqs" class="hash-link" aria-label="Direct link to FAQs" title="Direct link to FAQs" translate="no">​</a></h2>
<div class="olake-faq"><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q1. What is an ETL pipeline?</span></summary><div class="olake-faq__answer">It's an automated process that copies data from your source systems, cleans and reshapes it, and loads it into a place built for analysis, such as a data warehouse. It runs on a schedule or a trigger, so nobody has to move the data by hand.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q2. What does ETL stand for?</span></summary><div class="olake-faq__answer">Extract, transform, load. Extract means copy from the source, transform means clean and reshape, and load means write to the destination. For a bit of history, IBM says the process was introduced in the 1970s and later became the main method for data warehousing projects.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q3. What is the difference between an ETL pipeline and a data pipeline?</span></summary><div class="olake-faq__answer">A data pipeline is any automated movement of data. An ETL pipeline is one kind, the kind that transforms data before loading it. Other kinds load first and transform later (ELT), stream data as it arrives, or simply copy data without changing it.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q4. Is ETL batch or real time?</span></summary><div class="olake-faq__answer">Not only batch. Batch is the traditional style, but Google Cloud says streaming ETL pipelines now exist, and IBM uses the term streaming ETL. Microsoft also notes that the three steps often run in parallel rather than one after another.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q5. What is the difference between ETL and ELT?</span></summary><div class="olake-faq__answer">It comes down to where the transformation happens. In ETL it runs before loading, in a separate engine. In ELT the raw data is loaded first and transformed inside the destination. Microsoft says that location is the only difference between them.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q6. Is ETL outdated?</span></summary><div class="olake-faq__answer">Not according to the sources we read. IBM says ETL remains popular because it works with legacy systems, can improve data quality and can mask sensitive data in transit. Microsoft and AWS also list cases where ETL fits better than ELT.</div></details><details class="alert olake-faq__item"><summary><span class="olake-faq__question">Q7. What are common ETL pipeline problems?</span></summary><div class="olake-faq__answer">The usual suspects are duplicate rows after a retry, half-finished loads, missed deletes, late data and silent errors. Airflow's documentation advises making each task safe to re-run, using an upsert instead of a plain insert, and reading a specific partition rather than the latest data.</div></details></div>
<aside class="not-prose my-10 rounded-[16px] border border-solid border-olake-line bg-olake-surface p-[24px] lg:p-[32px]"><p class="m-0 text-[22px] leading-[1.2] tracking-[-0.01em] text-olake-ink lg:text-[26px]">OLake Go</p><p class="m-0 mt-[10px] max-w-[620px] text-[15px] leading-[1.6] text-olake-text-2">Replicate databases, Kafka, and S3 into Apache Iceberg with OLake Go, an open source EL engine built for Iceberg from the ground up.</p><div class="mt-[20px] flex flex-wrap gap-[10px]"><a href="https://olake.io/contact/" class="lk-press inline-flex h-[38px] items-center justify-center gap-[8px] rounded-[8px] border border-solid px-[16px] text-[14px] no-underline transition-colors border-olake-blue-ring bg-olake-blue text-olake-on-blue! hover:border-olake-blue-hover hover:bg-olake-blue-hover hover:text-white!"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="13" width="13" xmlns="http://www.w3.org/2000/svg"><path d="M224,104a8,8,0,0,1-16,0V59.32l-66.33,66.34a8,8,0,0,1-11.32-11.32L196.68,48H152a8,8,0,0,1,0-16h64a8,8,0,0,1,8,8Zm-40,24a8,8,0,0,0-8,8v72H48V80h72a8,8,0,0,0,0-16H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V136A8,8,0,0,0,184,128Z"></path></svg>Signup</a><a href="https://olake.io/slack/" target="_blank" rel="noopener noreferrer" class="lk-press inline-flex h-[38px] items-center justify-center gap-[8px] rounded-[8px] border border-solid px-[16px] text-[14px] no-underline transition-colors border-olake-btn-border bg-olake-surface text-olake-btn-secondary! hover:bg-olake-surface-alt hover:text-olake-ink!"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="15" width="15" xmlns="http://www.w3.org/2000/svg"><path d="M221.13,128A32,32,0,0,0,184,76.31V56a32,32,0,0,0-56-21.13A32,32,0,0,0,76.31,72H56a32,32,0,0,0-21.13,56A32,32,0,0,0,72,179.69V200a32,32,0,0,0,56,21.13A32,32,0,0,0,179.69,184H200a32,32,0,0,0,21.13-56ZM72,152a16,16,0,1,1-16-16H72Zm48,48a16,16,0,0,1-32,0V152a16,16,0,0,1,16-16h16Zm0-80H56a16,16,0,0,1,0-32h48a16,16,0,0,1,16,16Zm0-48H104a16,16,0,1,1,16-16Zm16-16a16,16,0,0,1,32,0v48a16,16,0,0,1-16,16H136Zm16,160a16,16,0,0,1-16-16V184h16a16,16,0,0,1,0,32Zm48-48H152a16,16,0,0,1-16-16V136h64a16,16,0,0,1,0,32Zm0-48H184V104a16,16,0,1,1,16,16Z"></path></svg>Join Slack</a><a href="https://github.com/datazip-inc/olake" target="_blank" rel="noopener noreferrer" class="lk-press inline-flex h-[38px] items-center justify-center gap-[8px] rounded-[8px] border border-solid px-[16px] text-[14px] no-underline transition-colors border-olake-btn-border bg-olake-surface text-olake-btn-secondary! hover:bg-olake-surface-alt hover:text-olake-ink!"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 256 256" aria-hidden="true" height="15" width="15" xmlns="http://www.w3.org/2000/svg"><path d="M208.31,75.68A59.78,59.78,0,0,0,202.93,28,8,8,0,0,0,196,24a59.75,59.75,0,0,0-48,24H124A59.75,59.75,0,0,0,76,24a8,8,0,0,0-6.93,4,59.78,59.78,0,0,0-5.38,47.68A58.14,58.14,0,0,0,56,104v8a56.06,56.06,0,0,0,48.44,55.47A39.8,39.8,0,0,0,96,192v8H72a24,24,0,0,1-24-24A40,40,0,0,0,8,136a8,8,0,0,0,0,16,24,24,0,0,1,24,24,40,40,0,0,0,40,40H96v16a8,8,0,0,0,16,0V192a24,24,0,0,1,48,0v40a8,8,0,0,0,16,0V192a39.8,39.8,0,0,0-8.44-24.53A56.06,56.06,0,0,0,216,112v-8A58.14,58.14,0,0,0,208.31,75.68ZM200,112a40,40,0,0,1-40,40H112a40,40,0,0,1-40-40v-8a41.74,41.74,0,0,1,6.9-22.48A8,8,0,0,0,80,73.83a43.81,43.81,0,0,1,.79-33.58,43.88,43.88,0,0,1,32.32,20.06A8,8,0,0,0,119.82,64h32.35a8,8,0,0,0,6.74-3.69,43.87,43.87,0,0,1,32.32-20.06A43.81,43.81,0,0,1,192,73.83a8.09,8.09,0,0,0,1,7.65A41.72,41.72,0,0,1,200,104Z"></path></svg>Explore OLake GitHub</a></div><p class="m-0 mt-[16px] text-[13px] text-olake-muted">Contact us at <strong class="font-medium text-olake-text-2">hello@olake.io</strong></p></aside>]]></content:encoded>
            <author>hello@olake.io (Priyansh Khodiyar)</author>
            <category>ETL</category>
            <category>Data Pipeline Tools</category>
            <category>Data Ingestion</category>
        </item>
    </channel>
</rss>