These three terms get used almost interchangeably in vendor decks, which is exactly why the distinction is worth being precise about. They're not three tiers of the same thing, they're three different answers to the question "where does data live before someone can query it, and what guarantees do you get when they do." Here's the technical version, no marketing language.

Data warehouse

A data warehouse stores structured data in a schema defined before the data is written — schema-on-write. Data is transformed and conformed into a dimensional model (or at least a well-defined relational one) as part of the load process, so by the time it lands, it's already shaped for query. The engine underneath is typically a relational or MPP columnar store — SQL Server, Redshift, Synapse dedicated pools, Exasol — with strong transactional guarantees, mature SQL support, and query optimizers built for exactly the kind of aggregation and join patterns BI tools generate.

The tradeoff is rigidity. Adding a new data source means designing its target schema first. Loading semi-structured or unstructured data (JSON blobs with variable shape, images, free text) doesn't fit well — you either flatten it lossily on the way in or you don't store it there at all.

Data lake

A data lake stores files — often in an open columnar format like Parquet, but also CSV, JSON, Avro, images, logs, anything — in cheap object storage (ADLS Gen2, S3) without requiring a schema to be defined at write time. This is schema-on-read: the structure is interpreted by whatever engine reads the file, not enforced by whatever process wrote it.

This buys enormous flexibility — you can land raw data from any source immediately, in its native shape, and decide how to model it later, which matters when you don't yet know every downstream use case. It costs you the guarantees a warehouse gives you for free: no built-in transactional consistency across files, no enforced constraints, no native concept of "this table just got updated correctly and atomically." Two processes writing to the same lake location at the same time can produce inconsistent reads. Historically this meant a lake was where raw and intermediate data lived, and a warehouse (often downstream of the lake) was where trusted, query-ready data lived — the classic "lake for storage, warehouse for serving" split.

Lakehouse

A lakehouse is what you get when you add a transactional metadata layer on top of lake storage — Delta Lake, Apache Iceberg, or Apache Hudi are the concrete implementations, and this is exactly what Microsoft Fabric's OneLake and its Delta-based Lakehouse item are built on. That metadata layer gives files in object storage the properties that used to require a real warehouse engine: ACID transactions, schema enforcement and evolution, time travel/versioning, and the ability to run set-based updates and deletes against what is still, physically, a folder of Parquet files.

The practical effect is that you get warehouse-like reliability and BI-query performance directly against data that's still stored in the open, cheap, engine-agnostic format a lake uses — which means a Spark job, a SQL engine, and a Power BI DirectLake connection can all read the same physical files without three separate copies of the data existing. That last point is the actual technical unlock, not a buzzword: one copy of the data, multiple compute engines reading it consistently, no ETL step required purely to move data from "lake shape" into "warehouse shape."

PropertyData WarehouseData LakeLakehouse
Schema enforcementSchema-on-write, enforcedSchema-on-read, not enforcedEnforced via metadata layer (Delta/Iceberg), still on lake storage
Transactional guaranteesStrong (ACID, native to engine)None nativelyACID via transaction log on top of files
Storage formatProprietary engine storageOpen files (Parquet, CSV, JSON, etc.)Open files (Parquet) plus transaction log
Best forCurated, query-ready structured data at scaleRaw/semi-structured ingestion, unknown future useBoth — raw-to-curated in one storage layer
Update/delete supportNative, row-levelDifficult, typically full file rewritesNative, row-level, via the transactional layer
Typical query engineSQL engine tightly coupled to storageAny engine that can read the file formatAny engine, reading the same physical files

When you'd genuinely need each

A pure data warehouse is the right call when your sources are already structured (ERP tables, CRM exports, transactional databases), your reporting requirements are well understood, and you want the strongest possible guarantee that a finance report run twice in a row returns the same numbers with no surprise from an in-flight write. Star-schema reporting at scale, where DAX or SQL aggregation performance is the top priority, is a warehouse-shaped problem.

A pure data lake earns its place when you're ingesting high-volume, variably-structured data — device telemetry, clickstream logs, third-party API payloads with shifting fields — and you genuinely don't know yet which parts will matter for analytics. Landing it cheaply and figuring out the model later is the right sequencing, especially when the volume would make schema-on-write transformation prohibitively expensive to run on everything up front.

A lakehouse is the right call when you want both: you're bringing in a mix of structured and semi-structured sources, you want a single storage layer that multiple teams and multiple engines (a data science notebook, a SQL analyst, a Power BI report using DirectLake) can all query consistently, and you don't want to maintain a separate ETL hop whose only job is copying data from lake format into warehouse format. In a Fabric-based architecture specifically, this is the default shape now — land data into OneLake, model it in a Lakehouse or Warehouse item, and let Direct Lake mode read the Delta files without a full import refresh, which collapses a step that used to require its own scheduled pipeline.

The question that actually matters isn't "warehouse or lake or lakehouse," it's "who needs to write to this data, who needs to read it, and does anyone need a transactional guarantee while both are happening at once." Answer that, and the right storage layer is usually obvious.

None of these three has made the other two obsolete, despite what a lakehouse vendor's slide deck might imply. A lakehouse solves the specific pain of maintaining separate lake and warehouse copies of the same data — it doesn't mean every workload needs one, especially if your sources are already clean and structured and your only consumer is a BI tool that was always going to want a well-modeled star schema regardless of what's underneath it.