ETL/ELTWAREHOUSE-SPECIFICTOOL-SPECIFICGENERAL

ELT: Load First, Transform Where the Data Lives

Extract, load, transform. The destination holds the raw copy and does the work — which turns most transformation bugs into a re-run and hands the destination every obligation the raw data carries.

Who needs this, what one row is, and why the obvious build breaks

Every lesson starts from the consumer, because designing from the source outward is this domain's characteristic mistake.

The question

What does a pipeline gain by loading data it has not yet cleaned, and what does the destination inherit the moment it does?

Who needs this

Two consumers with different needs. The analyst wants curated models with a stable contract and never wants to see the raw layer. The data engineer wants the raw layer to exist and be complete, because it is the input to every fix they will ever make. ELT is the shape that serves both from one system, which is its real appeal and the source of most arguments about who may query what.

What one row is

One raw record, as delivered, inside the destination. Under ELT the raw layer's grain is *the source's* grain — one CDC change, one API page item, one event — and not yet the analytical grain. The whole transformation layer exists to move from that grain to one that answers business questions, and confusing the two is how a COUNT(*) against a raw table becomes a headline number (Grain: What Does One Row Represent?).

The obvious build

Point a managed connector at the source, let it replicate tables into the warehouse on a schedule, and write SQL views on top. There is no transformation code to operate, no cluster to size, and an analyst can start working the same afternoon. For a company with a handful of SaaS sources this is a legitimately excellent answer and it is why the pattern spread.

Why it breaks

The views work until someone stacks a view on a view on a view. Nothing is materialised, every dashboard re-derives the whole chain at query time, and the same expensive scan runs a hundred times a day because it was never anybody's job to persist the middle (Model Layering).

How it breaks with real data
  • The views work until someone stacks a view on a view on a view. Nothing is materialised, every dashboard re-derives the whole chain at query time, and the same expensive scan runs a hundred times a day because it was never anybody's job to persist the middle (Model Layering).
  • The connector replicates a table containing a plaintext email column. It now exists inside an analytical system with far broader access than the operational database it came from, and no one made a decision about that — the connector did (PII in Pipelines).
  • A transformation bug is found. The fix is easy, but nobody knows which downstream models depend on the corrected table, so the re-run either misses half the platform or rebuilds all of it (Impact Analysis).
  • The raw layer is treated as queryable. An analyst writes a metric against raw_orders directly, at the source's grain, counting CDC change records as orders, and presents a number three times too large with complete confidence (Duplicate Rows).
  • Transformation now competes with querying for the same warehouse compute. The nightly model build and the morning dashboard load collide, and the fix is either scheduling discipline or paying for isolation (Workload Isolation).
  • A deletion request arrives. The row must be removed from the operational database, the raw layer, every staging model, every curated table and every extract downstream of them — and the raw layer is the part that makes the other four impossible to declare finished (Deletion Requests).
SourceIngestionRawTransformationValidationStorage ModelServingConsumerObservability

What is actually happening

  • ELT reorders exactly one thing: the transform moves *after* the load, which means it also moves *into* the destination. The extract is unchanged and the load now carries source-shaped data instead of curated data.
  • The consequence people cite is performance — the warehouse's query engine is a well-optimised distributed processor and using it for transformation is using a good tool you already have (Query Engines, Columnar Execution). That is true and it is not the important part.
  • The important part is that the raw copy is retained inside the system that does the work. A transformation bug becomes a re-run against data you already hold, not a re-extract from a source that has mutated. This single property is the reason ELT changed how teams fix mistakes, and it is available under ETL too — by landing raw first (Keeping Raw History: The Recovery Position and the Liability).
  • What makes it practical is that transformation becomes SQL. SQL is declarative, reviewable, testable, and the engine chooses the execution plan, so the transformation layer becomes a dependency graph of named models rather than a set of imperative scripts (SQL Transformations, The Transformation DAG).
  • It became practical *because* destination compute stopped being a fixed appliance. Separating storage from compute made it possible to hold raw data you rarely query without paying for capacity to query it, and to scale the transform independently of the serving load (Separating Storage from Compute).
  • The obligations move with the data. Classification, retention, access control and deletion all now apply inside the analytical system, to a copy that is more widely readable than the original. ELT does not create that problem; it relocates it into a system whose access model was designed for openness (Data Access Control).

The same three steps, reordered — and what moves with them

Swapping two letters sounds like a small change. It is not, because the transform does not merely move later in time — it moves into a different machine, a different billing envelope, a different access model and a different team's operational responsibility. Everything downstream of "load" is now the destination's problem, including obligations the destination was never designed to carry.

Read the guarantee column below against the same column in ETL: Transform Before the Data Lands. The promises are not weaker or stronger; they are located differently. Under ETL, the promise "the destination contains only conformed rows" is structural. Under ELT it does not exist at all, and is replaced by "everything that arrived is still here", which is a promise about recovery rather than about cleanliness.

The stage that carries the most weight is the raw layer, and the one that carries the most risk is also the raw layer. It is simultaneously the reason the pattern works and the dataset a security review will ask about first.

ELT as four steps, with the transform inside the destination
  1. 1
    Extract

    Reads changes or snapshots from the source, usually via a connector rather than bespoke code.

    guarantees Only what the connector's mode promises: a CDC connector promises committed changes at least once, a snapshot connector promises current state as of a moment (CDC vs Polling).

    fails by A connector restarting from a fresh snapshot after an outage, re-emitting history and leaving a gap where the outage was.

  2. 2
    Load into raw

    Writes delivered records into the destination, untransformed, typically append-only and partitioned by load time.

    guarantees That every delivered record is retained and reprocessable. Not that every source record was delivered.

    fails by Being configured to overwrite rather than append, which produces a mirror of current state and quietly deletes the history the pattern depends on.

  3. 3
    Transform in place

    Runs SQL models inside the destination: dedupe, cast, conform, join, aggregate, model into facts and dimensions.

    guarantees That the models compiled and ran in dependency order, and that any tests you attached passed.

    fails by A fan-out join, a filter that drops a category, or a window function whose ordering is non-deterministic under ties.

  4. 4
    Serve curated

    Exposes the modelled tables consumers are allowed to query, with documented grain and owner.

    guarantees A stable contract, if you declared one. By default: nothing beyond "this table exists".

    fails by Consumers routing around it to a staging model for freshness, thereby skipping every test the curated layer carries (Data Contracts).

Two stages here have no analogue in ETL: raw, which is what buys recoverability, and serve-curated, which is what stops consumers from reading raw. Platforms that build the first and skip the second get the storage cost and the governance risk without the safety.

Transformation becomes a graph of SQL models

ENGINE-SPECIFICWhether ROW_NUMBER() deduplication is the efficient choice depends on the engine: some warehouses optimise this pattern heavily, while on an engine without good window-function pushdown a QUALIFY clause or a merge-on-read table format performs very differently for the same logical result.

Once the transform runs inside the destination, it is written in the destination's language, and for a warehouse that means SQL. This is a bigger deal than it sounds: SQL is declarative, so the engine picks the plan; it is reviewable in a pull request; it is testable against fixtures; and a set of SELECT statements that reference each other by name is already a dependency graph without anyone designing one (DAG (Directed Acyclic Graph)).

That graph is what makes targeted recovery possible. When a bug is found in one model, the graph says exactly which models are downstream and therefore which need rebuilding — and equally which do not, which is the half that saves money and avoids changing numbers nobody asked you to change.

It is also where the pattern's characteristic mistake lives. Because a model is cheap to add, layers accumulate: a staging model on raw, a cleaned model on staging, an enriched model on cleaned, a mart on enriched, and a dashboard that joins two marts. If none of the middle is materialised, every dashboard load re-derives the entire chain from raw.

What each layer holds and what it can corrupt
  1. Source `orders`

    holds Authoritative current state of every order.

    could corrupt Nothing this domain owns — if it is wrong here it is an application incident, not a data one (Source of Truth).

    ↑ reads from
  2. Connector

    holds A position in the source's change log, or a snapshot schedule.

    could corrupt Gaps from outages, re-emitted history after a snapshot restart, silently dropped tables after a permission change.

    ↑ reads from
  3. `raw_orders`

    holds Every delivered change record, with duplicates, in load order.

    could corrupt Nothing by itself — but being queried directly, at the wrong grain, by someone who found it in the catalog.

    ↑ reads from
  4. `stg_orders`

    holds One row per order, latest change, conformed types.

    could corrupt Choosing "latest" by arrival instead of commit position; dropping deletes so cancelled orders live forever.

    ↑ reads from
  5. `fct_orders`

    holds One row per order at the declared analytical grain, with business rules applied.

    could corrupt A fan-out join against a dimension with duplicate keys; a revenue rule that changed without history being rebuilt.

    ↑ reads from
  6. Dashboard

    holds One aggregated number and a filter set defined in the BI tool.

    could corrupt A filter or join added in the BI layer that no model, test or lineage graph can see (Where the Transformation Actually Runs).

Every hop after the connector is inside one system and inside your control. That is the concrete meaning of "ELT makes bugs recoverable": five of the six rows can be rebuilt from a row above them.

Three layers of one ELT transformation, each with one job
1-- raw: exactly what the connector delivered. Append-only.
2-- grain: one CDC change record. Duplicates expected.
3-- nobody queries this except the pipeline.
4
5-- staging: one row per order, source-shaped names conformed.
6CREATE OR REPLACE VIEW stg_orders AS
7SELECT order_id,
8 customer_id,
9 CAST(amount_minor AS BIGINT) / 100.0 AS amount,
10 CAST(occurred_at AS TIMESTAMP) AS ordered_at,
11 status
12FROM (
13 SELECT *,
14 ROW_NUMBER() OVER (PARTITION BY order_id
15 ORDER BY source_lsn DESC) AS rn
16 FROM raw_orders
17) d
18WHERE d.rn = 1 -- dedupe: latest change per order
19 AND d.op <> 'delete'; -- deletes are represented, not silently dropped
20
21-- curated: the analytical grain, with the business rule made explicit.
22CREATE OR REPLACE TABLE fct_orders AS
23SELECT o.order_id,
24 o.customer_id,
25 o.ordered_at,
26 o.amount,
27 o.status IN ('shipped','delivered') AS is_revenue_recognised
28FROM stg_orders o;

Two things to notice. The dedupe orders by the source's log position, not by arrival — arrival order is not commit order and choosing it makes an out-of-order update win (CDC Ordering and Transaction Boundaries). And the revenue rule lives in one named column in one model, so there is exactly one place to look when someone disputes the number (The Metrics Layer).

What loading first actually costs

The honest account of ELT includes the parts that do not appear in the diagram. Raw data in the warehouse is data in a system built for broad access, holding fields the operational database guarded, retained for a window chosen for engineering reasons by people who were not thinking about subject access requests. None of that is an argument against the pattern; all of it is an argument for deciding it deliberately.

The operational costs are more mundane and more certain. Transformation competes with querying. Models proliferate. Nobody deletes anything. The warehouse bill grows in a way that is hard to attribute until someone builds attribution, and by then there are three hundred models and four people who know what any of them are for.

The failure table below is the set of ELT-specific incidents worth recognising on sight. Each one has an obvious response and a non-obvious cause, and the reason they recur is that the pattern makes the wrong thing easy rather than making the right thing hard.

Where an ELT platform actually spends, relative to each other
Model builds scanning more than they changed

Full refreshes and unpartitioned incremental models. The largest line in most warehouses and the one with the clearest fix.

Consumer queries over unmaterialised chains

Each dashboard load re-deriving several layers. Grows with dashboard count rather than with data volume.

Retained raw storage

Small, permanent, and the line that buys the recovery window. Cut it and you have converted a re-run into an apology.

Load and connector compute

Usually modest, and usually the first thing anyone tries to optimise because it is the easiest to see.

Relative weights, not measurements. The ordering is what transfers between platforms; the magnitudes do not, and this domain never publishes a price.

Relative weights to establish an ordering for a typical warehouse-centric ELT platform, not measurements. The ordering is the lesson: the expensive part is transformation reading more than it needed, and the cheap part is the storage everyone proposes deleting.

ELT-specific failures and what they actually are
TriggerSymptomCauseResponse
Dashboards get slower every month with no schema change.Query time grows steadily; warehouse compute grows with it.A view-on-view chain that was never materialised, so each dashboard re-derives the full lineage from raw on every load.Materialise the models with the highest read-to-build ratio. Measure bytes scanned per model, not per query, so the culprit is a name rather than a hunch.
A metric is triple its true value.Revenue looks implausible; row counts in the fact table exceed orders in the source.A model reading raw_* directly, counting CDC change records as business events.Revoke consumer access to raw and enforce the boundary in the catalog. The naming convention is not the control; the grant is.
Model builds and morning dashboards are both slow.Queues in the warehouse; both workloads degrade together.Transformation and serving sharing one compute pool, with the build schedule overlapping the business day.Separate the pools if the warehouse supports it, or move the heavy builds off the read peak. Confirm the separation is real by attributing spend, not by reading configuration.
A deletion request cannot be completed.Legal asks for confirmation; engineering cannot give a date.Raw stored as immutable files with no row-level delete, and no index of which files contain which subject.Move raw to a table format supporting deletes, or partition by something that makes targeted rewrite bounded. Decide this before the first request, because afterwards it is an incident.
A model builds successfully against data that stopped updating.Everything green; the dashboard shows a flat line since Tuesday.The connector lost access to a source table and reported the failure only in its own logs.Freshness checks on raw tables, not just on curated models. The build cannot detect an input that is stale rather than absent (Freshness Checks).

How to build it

Most important first.

  • Make the raw layer append-only and off-limits to consumers. It exists to be reprocessed from, not queried — its grain is the source's, its quality is unvalidated, and every metric written against it will be wrong in a way that looks right (Raw, Staging, Curated: Layers by Purpose).
  • Express transformations as named, dependency-ordered models with tests attached, not as a pile of scheduled CREATE TABLE AS statements. The dependency graph is what makes a targeted re-run possible at all (dbt Concepts).
  • Materialise deliberately. A view costs nothing to build and everything to query repeatedly; a table costs a build and makes the query cheap. Choose per model based on how often it is read and how expensive it is to derive (Compute Waste).
  • Filter classified fields at load time even under ELT. "Load everything" is a default, not a law, and there are fields whose presence in the warehouse is itself the incident (Data Minimization).
  • Make every model incremental where the underlying data is append-mostly, and be explicit about the late-arriving case. Full rebuilds are wonderfully simple and they stop being affordable exactly when the dataset becomes important (Full Refresh vs Incremental).
  • Give the raw layer a retention policy that is argued as a recovery window, and the curated layer one that is argued from consumer need. They are different questions with different answers, and conflating them is how platforms end up keeping everything forever (Data Retention).

What this actually promises

Naming the guarantee you do not have is worth more than naming the one you do — everything downstream inherits the weakest promise in the chain.

  • The raw layer guarantees that what the connector delivered is preserved. It does *not* guarantee that what the connector delivered is what the source held — a connector gap, a missed DDL change or a snapshot restart are all invisible from inside the warehouse (CDC Failure Modes and the Retention Deadline).
  • Delivery into raw is typically at-least-once, so raw contains duplicates by design. Deduplication is a transformation step, and any consumer reading raw directly is reading a multiset (Deduplication).
  • Transformations are deterministic with respect to their inputs *if* they avoid the clock, avoid non-deterministic ordering in window functions, and read snapshots rather than tables under concurrent write. Each of those is easy to violate by accident (Determinism: Same Input, Same Output?).
  • Publish atomicity is per model and depends on how the model is materialised. A dependency graph of ten models has ten publish points unless you built a single swap, so a consumer joining two of them can observe a mismatched pair (Atomic Publish).
  • Nothing guarantees the curated layer means what its column names suggest. SQL that runs is not SQL that is right, and the warehouse will compute a wrong metric as efficiently as a correct one (Two Dashboards, Two Numbers).

Can I trust it?

A green pipeline is evidence that code ran. These four fields are the evidence that the data is right.

The check that would catch this
  • Test at the boundary between raw and staging: uniqueness on the business key, not-null on the fields the models assume, accepted values on every enumerated column, and a referential check against the dimension a model joins to. These are the assumptions the transformation layer silently makes; writing them down converts a wrong number into a failed build.
  • A second check compares raw row counts per period against the source's own counts, because everything inside the warehouse is downstream of the connector and cannot see what the connector missed (Reconciliation).
  • They miss semantic drift completely. A status column that gains a new value passes not-null, passes uniqueness, fails no referential check, and quietly falls into whatever the transformation's ELSE branch does (Semantic Changes).
Freshness
  • ELT makes the *raw* layer as fresh as the load allows, and the curated layer as fresh as the model build schedule. Consumers experience the second number and are frequently quoted the first (Freshness Monitoring).
  • Because transformation is decoupled from ingestion, freshness becomes tunable per model: a critical model can rebuild frequently while a heavy one rebuilds nightly, without touching the load. That flexibility is one of the genuine advantages of the ordering.
  • The transformation graph's critical path sets the floor. A model six levels deep cannot be fresher than the slowest ancestor plus its own build, and the deepest path is rarely the one anybody is watching.
  • Raw being fresh is a trap for consumers. A dashboard that quietly reads a staging model to get better freshness has opted out of every test attached to the curated layer (Data Tests).
When the schema or meaning changes
  • A new source column arrives in raw whether anyone planned for it or not, which is ELT's best evolution property: the field is captured before anyone knew they needed it, and a model can start using it retroactively across the whole retained history (Schema Evolution).
  • A removed or renamed source column breaks the models that referenced it, loudly, at build time — provided the models reference columns explicitly. A model built on SELECT * propagates the change silently into every table downstream (Breaking Schema Changes).
  • A retype at the source may or may not break the load depending on how the raw layer is typed. A raw layer that stores payloads as semi-structured data absorbs almost anything and defers every failure to the first model that casts (Nullability & Defaults).
  • Changing a curated model's definition changes history only if you rebuild history. Because ELT usually *can* rebuild history, the discipline question becomes "should we" — and silently redefining three years of a metric is its own kind of incident (Reprocessing vs Retrying).
How to re-run this safely
  • The recovery story is the point of the pattern: fix the model, re-run the affected range from raw, validate, publish. No source is touched and no other team is involved (Planning a Backfill).
  • It only holds while raw is intact and complete for the period being fixed. A raw layer with a retention window shorter than the age of your worst undiscovered bug is a recovery story with an expiry date.
  • Targeted re-runs need the dependency graph. Without it the choice is between rebuilding everything, which is expensive and risks changing unrelated numbers, and rebuilding by hand, which misses something (Topological Execution).
  • Re-running a model that is not idempotent is how a fix doubles a metric. Incremental models are the usual offender: appending the corrected range without first removing the wrong one leaves both (Idempotent Data Pipelines).

What can go wrong

Failure modes
  • View stacking: an elegant-looking layered model where nothing is materialised, so every dashboard pays for the entire lineage on every load (Scan Cost).
  • Raw queried as though it were curated, at the source's grain, by someone who found it in the catalog and reasonably assumed a table in the warehouse was meant to be used.
  • Transformation load and query load competing, so the platform is slowest exactly when people are using it.
  • The mitigation failing: a warehouse feature that isolates transformation compute from query compute, configured once and then quietly outgrown, so the isolation exists in the diagram and not in the bill (Cost Attribution).
  • A deletion request that cannot be satisfied because the raw layer is append-only object storage with no row-level delete, and nobody checked that before promising a compliance timeline.
  • A connector that silently drops a table after a source-side permission change, so a model builds successfully against a raw table that stopped updating on Tuesday (Stale Dashboards).
Misreads
  • "ELT is the modern, correct pattern." It is one answer to where compute lives and who holds the raw copy. Where a boundary forbids the raw data from landing, or the destination cannot read the format, ELT is not available at all (ETL vs ELT: Choosing by Constraint, Not by Fashion).
  • "We do ELT, so we have raw history." Only if the raw layer is retained, complete and immutable. A connector configured to replicate current state rather than changes gives you a fresh mirror and no history whatsoever (Snapshot and Stream: the Bootstrap Problem).
  • "The warehouse is fast, so transformation is free." Transformation is the largest scan in most platforms. Fast means the query returns; it does not mean the work was small.
  • "SQL transformations cannot have bugs like scripts do." A LEFT JOIN against a dimension with duplicate keys multiplies every measure in the fact table, and the query succeeds (Fact Tables).
  • "Loading everything is the safe default." It is the safe default for recoverability and the unsafe default for privacy, and those two are decided by different people who often never meet (Data Governance).
Privacy, retention and access
  • The raw layer is the highest-risk dataset most platforms hold: source-shaped, unfiltered, complete, and inside a system whose whole purpose is broad analytical access. Its access controls should be the tightest in the platform, not the loosest.
  • Loading before deciding what may be loaded inverts data minimisation. The minimisation decision still has to happen; ELT just moves it to after the data is already in the system, where it is a deletion problem rather than a filter.
  • Deletion under ELT must be planned for at the storage layer. A raw layer on an open table format supports row-level deletes; one on plain immutable files does not, and rewriting affected files is the only path (Open Table Formats).
  • Column-level classification on raw tables is what lets masking and row-level policies apply automatically to everything derived from them. Applied later, it has to be re-derived for every model by hand (Data Classification).

Operating it

How you see it in production
  • Freshness per raw table and per curated model as two separate signals, because the gap between them is the number consumers actually experience and the number nobody publishes.
  • Bytes scanned per model build and per dashboard, attributed to a model name. This is the single measurement that turns "the warehouse got expensive" into a list of three models to fix.
  • The transformation graph's critical path duration over time. It grows slowly and monotonically until the night it does not finish before the morning (Pipeline Observability).
  • Test failures as a rate per model, not just as a pass/fail gate — a test that has been failing and being ignored for a month is worse than no test (Quality Alerting).
What changes at 10x and 100x
  • At 10x, full-refresh models stop fitting the schedule and incrementality becomes mandatory. This is the most predictable scaling event in the entire pattern and it always arrives sooner than the team expects (Incremental Processing).
  • At 100x, physical layout inside the warehouse dominates: partitioning and clustering decide what a model build reads, and a model that reads everything to update one day is the definitive expensive mistake (Partition Pruning).
  • Model count scales the governance problem rather than the compute one. Five hundred models with unclear ownership and no lineage is a different failure from a slow query, and no amount of compute fixes it (Data Ownership).
  • Consumer count changes what needs materialising. A model queried twice a week should be a view; the same model on eighty dashboards should be a table, and possibly a mart (Data Marts).
What drives cost here
  • Storage for a raw copy that is rarely read. This is usually the smallest line and always the first one someone proposes deleting, which is the wrong instinct: it is buying the recovery window (Storage Lifecycle).
  • Compute for transformation, charged by what the queries scan and shuffle. Full rebuilds of large models dominate this line, and incrementality is the lever with the largest effect.
  • Compute for consumers, which ELT increases indirectly by making it easy to build models on models. Every additional layer is another scan, and a view-only architecture pays for the whole chain per query (What Actually Drives Data Platform Cost).
  • The cost that is not on any bill: transformation and serving share a resource pool, so a runaway model build degrades everyone's queries. That is a reliability cost paid in trust (Pipeline Reliability).
What this approach costs
  • ELT buys reprocessability and a single system to operate; it costs storage for data you may never query and hands the destination every governance obligation the raw data carries, in an environment with broader access than the source.
  • Using the warehouse for transformation means you do not operate a separate cluster, and it means transformation competes with querying unless you deliberately separate them. You have not removed the operational problem, you have changed which team owns it.
  • Loading first makes the pipeline simple and makes "what is in our warehouse" a question nobody can fully answer without a catalog. That is a real cost and it lands on the security and privacy side of the house rather than on the engineering side (The Data Catalog).

Model graph explorer

Change an input and watch which number moves — and which one does not. Everything here comes from a model in this repository, not from a measurement.

Model graph explorer
A transformation project is a graph of models, and the layer a model sits in is a promise about what may depend on it.
Source
Staging
Intermediate
Mart
Exposure
selectedupstreamdownstream
fct_orders
LayerMart — A stated grain and a stable set of columns. This is the layer a consumer is allowed to depend on, which is exactly why changing it is expensive.
One row isOne order, with measures and dimension keys.
Materialised asincremental
Depends on
Depended on by
The number that matters for a change is not how many models exist but how many sit below this one. Editing fct_orders puts 3 models at risk, and the ones in the exposure layer are the ones a person will notice.
TOOL-SPECIFICThe `stg_` / `int_` / `fct_` convention is dbt's, and other tools name the same three ideas differently. What transfers is that the layers exist because different models make different promises, not because a style guide said so.

Where this applies

Almost nothing here is universal. These labels say what each claim is specific to, and where a different engine, format, warehouse or scale would differ.

  • WAREHOUSE-SPECIFICWhether ELT is practical depends on the destination separating storage from compute and scaling transformation independently of serving. A fixed-capacity analytical database can technically do ELT and will simply starve its own queries, which is why the pattern was rare before that architecture existed.
  • TOOL-SPECIFICThe dependency graph, tests and lineage that make ELT manageable come from the transformation tool rather than the warehouse; a platform running the same SQL as scheduled statements has ELT's costs without its targeted re-run or impact analysis.
  • GENERALThe underlying property — that retaining an unmodified copy upstream of the transform turns a logic bug into a re-run — holds for any pipeline in any technology, which is why the same benefit is available to ETL that lands raw first.

Where the depth lives

This domain teaches how data moves and how you know it arrived intact. It hands the rest off by name.

Domains that do not exist yet
  • Distributed Systems owns what the connector's "at least once" actually costs you, and why a raw layer containing duplicates is the normal outcome of a correct system rather than a defect in it.
  • DevOps / Production Engineering owns the delivery pipeline for transformation code — pull requests, CI runs against a sample, promotion between environments, and the rollback that turns a bad model deploy into a revert instead of an incident.