Updated recently
Last updated:
Quick Answer: Databricks Auto Loader: Databricks Auto Loader is a managed ingestion feature that reads new files from cloud object storage incrementally, tracks what it has already processed in a checkpoint, and writes the result into a Delta table — so a rerun picks up only what arrived since last time, not the whole bucket. The two decisions that matter most are the ingestion mode (directory listing versus file notification) and the schema handling strategy. Use Auto Loader when files arrive continuously and need to be picked up within minutes; use COPY INTO when a scheduled batch load is enough; use Structured Streaming connectors when the source is a message bus rather than a file.
Key takeaways
- Auto Loader processes only new files since the last run, tracked by a checkpoint — this is what makes it incremental rather than a full re-read.
- Directory listing mode re-scans the prefix each time and is charged on storage list requests. File notification mode subscribes to bucket events and is faster and cheaper at scale, at the cost of extra cloud plumbing.
- Schema evolution is automatic by default. New columns are added; malformed rows are rescued into a separate column rather than failing the batch.
- The cost driver is per-file overhead, not per-byte. Thousands of tiny files cost far more than the same bytes in large files.
- It is a file ingestion tool. Live events from Kafka, Kinesis or Event Hubs need a streaming connector instead.
What this guide covers
- What Auto Loader actually does, and the three problems it removes
- Directory listing versus file notification, with the cost difference
- How checkpoints give you exactly-once behaviour
- Schema inference, schema evolution and the rescue data column
- The performance knobs that control batch size
- Auto Loader versus COPY INTO versus streaming connectors versus Volumes
- Ingesting media files and device telemetry — the honest architecture
- Governance, and what Unity Catalog changes
The problem: a bucket that keeps growing
Every lakehouse starts the same way. A producer writes files to a bucket. A job reads them. Then the producer starts writing more often, the file count climbs into the tens of thousands, and the ingestion job starts failing in three different ways.
First, it runs out of memory, because the naive version reads the entire bucket on every run. Second, it reprocesses files it has already handled, so downstream tables get duplicate rows unless every job is careful about deduplication. Third, it starts taking hours, and the team adds a second, larger cluster — which makes the bill worse without fixing the underlying problem.
The root cause is the same in all three cases: the ingestion logic has no memory of what it has already seen. Without that, every run is a full scan.
Auto Loader is the managed answer to exactly this problem, and the Databricks documentation on cloud object storage ingestion documents the two available options — Auto Loader and COPY INTO — along with when each one fits.
What Auto Loader actually does
Three jobs, and the third is the one people miss.
1. It discovers new files. It tracks files that have appeared in a storage location since the last checkpoint, using either a prefix listing or bucket event notifications.
2. It remembers what it processed. A checkpoint — a small metadata store, usually a table or a blob — records which files have been ingested. On the next run, the already-processed set is skipped. This is the mechanism that turns “read the bucket” into “read what is new.”
3. It infers and evolves the schema. It inspects the incoming data, builds a schema, and when later files contain new columns, it merges them into the schema rather than failing. Rows that do not fit the schema can be diverted to a rescue column instead of killing the batch.
The Auto Loader documentation covers the file-source options in detail, including the cloudFiles format options that control each of these behaviours.
In practice it looks like this:
from pyspark.sql import functions as F
events = (
spark.readStream
.format("cloudFiles")
.option("cloudFiles.format", "json")
.option("cloudFiles.schemaLocation", "s3://warehouse/schema/events")
.option("cloudFiles.inferColumnTypes", "true")
.option("cloudFiles.schemaChangeMode", "addNewColumns")
.option("rescueDataColumn", "_rescued_data")
.load("s3://warehouse/raw/events/")
)
(
events
.withColumn("event_ts", F.to_timestamp("event_ts"))
.withColumn("ingested_at", F.current_timestamp())
.drop("_rescued_data")
.writeStream
.option("checkpointLocation", "s3://warehouse/checkpoints/events")
.option("mergeSchema", "true")
.trigger(availableNow=True) # batch run; omit for continuous streaming
.start("bronze.events")
)
Three things in that snippet carry most of the weight. The schemaLocation is where the inferred schema is persisted, and it must be a stable path outside the data location — pointing it at the data folder means the schema gets rewritten on every run. The checkpointLocation is the memory of the pipeline; deleting it means re-ingesting everything. And availableNow=True switches it from continuous streaming to a batch run that processes the files currently available and then stops, which is the right default for most backfills and scheduled loads.
The same ingestion expressed in SQL:
CREATE TABLE bronze.raw_events (
device_id STRING,
event_ts TIMESTAMP,
latency_ms DOUBLE
) USING DELTA;
SELECT * FROM read_files('s3://warehouse/raw/events/', format => 'json')
The mode decision: directory listing vs file notification
This is the first real decision, and it is a cost and latency decision rather than a correctness one.
Directory listing mode is the default. On every run, Auto Loader lists the storage prefix, compares the result against the checkpoint, and processes what is new. The advantage is that it needs no extra infrastructure — point it at a path and it works. The disadvantage is that the listing cost is proportional to the number of files in the prefix, not the number of files you want to process. On a prefix with a million historical files, you pay a million list operations to discover the twelve new ones.
File notification mode changes the mechanism. Instead of listing, it subscribes to storage events — S3 event notifications into a queue on AWS, Event Grid notifications on Azure, Pub/Sub on Google Cloud — and the queue drives what gets processed. Listing disappears from the hot path, and files are picked up as they land rather than on the next listing cycle.
| Directory listing | File notification | |
|---|---|---|
| Extra infrastructure | None | Queue or topic plus a service relationship |
| Detection latency | Bounded by the listing interval | Near real time |
| Listing request cost | Grows with total file count in the prefix | Effectively removed from the path |
| Best at | Small prefixes, batch loads, low event volume | Large prefixes, high-volume landing, streaming |
| Operational risk | Low | The notification path can fail silently if misconfigured |
The practical rule: if the prefix will hold hundreds of thousands of files and files arrive continuously, move to file notification. The plumbing is a one-time setup and the savings compound daily.
The same decision has a cloud-specific shape. On AWS the queue is SQS fed by S3 event notifications, on Azure it is Event Grid feeding a Storage Queue or Event Hub, and on Google Cloud it is Pub/Sub on GCS. The Databricks documentation for Auto Loader on cloud object storage describes the event-driven setup per cloud.
Schema inference and the rescue data column
Schema drift is where ingestion quietly loses data. A producer adds a field, a nested object changes shape, a numeric column starts arriving as a string, and the batch either fails or — worse — silently drops the rows that do not fit.
Auto Loader’s default behaviour is to handle this rather than fail:
- Inference happens once, from the first batch of files, and the result is written to the
schemaLocation. - Evolution then applies. With
schemaChangeModeset toaddNewColumns, new fields appear in the target table automatically. Other modes exist for stricter control, including rejecting the change or overwriting the stored schema. - The rescue data column catches rows that cannot be parsed against the schema. Instead of the batch dying, the unparseable payload is kept as a string in
_rescued_data, and the row still lands in the table.
That last one is worth insisting on in production. A pipeline that silently drops rows is worse than one that fails loudly, because the failure surfaces at month-end reconciliation. With a rescue column, you get both — the row is preserved, and you can count how many rows needed rescuing:
SELECT count(*) AS rescued_rows
FROM bronze.events
WHERE _rescued_data IS NOT NULL
A non-zero number is not necessarily a problem. It is a measurement, and it should be on a dashboard rather than discovered by surprise. If you want to see the raw payload of a rescued row, parse it back out:
SELECT
device_id,
from_json(_rescued_data, 'map<string,string>') AS raw_payload
FROM bronze.events
WHERE _rescued_data IS NOT NULL
LIMIT 20;
Performance: the knobs that control batch size
Auto Loader’s throughput is governed by how much it processes per trigger. These are the settings worth knowing, and they are the difference between a pipeline that keeps up and one that falls behind.
| Setting | What it controls | When to raise it |
|---|---|---|
maxFilesPerTrigger |
Upper bound on files processed per trigger | Files are large, or the cluster can absorb more per batch |
minFilesPerTrigger |
Lower bound before a trigger fires | Arrival rate is high and you want fewer, larger batches |
maxBytesPerTrigger |
Byte cap per trigger | You need a hard ceiling on per-batch memory pressure |
trigger(availableNow=True) |
Run once over what is available, then stop | Scheduled batch loads and backfills |
trigger(processingTime=...) |
Interval-based continuous processing | True streaming from files |
Two practical notes. First, maxFilesPerTrigger is a ceiling, not a target — if only three files arrived, three get processed regardless. Second, for a scheduled batch, availableNow=True is usually the right choice over processingTime, because it processes everything currently available and terminates rather than holding a cluster open waiting for the next file.
The other half of throughput is file size, and this is the part people get wrong. The per-file overhead — listing, schema checks, task scheduling, commit overhead — dominates when files are small. A pipeline ingesting 12 GB as 120,000 files of 100 KB each costs vastly more than the same 12 GB as 120 files of 100 MB.
If you control the producer, change the producer. Ask for compressed columnar output, a target file size in the tens-to-hundreds of megabytes range, and a naming convention that sorts naturally by time. If you do not control the producer, then compaction becomes your job — see the Z-Ordering and pipeline optimization guide for the maintenance side of this.
Auto Loader, COPY INTO, streaming connectors or Volumes
Four ways to get data in, and they are not interchangeable.
| Approach | Use when | Latency | Operational weight |
|---|---|---|---|
| Auto Loader | Files land continuously and you want them picked up in minutes | Minutes | Low — no extra infrastructure in listing mode |
| COPY INTO | A scheduled batch load is enough; you want pure SQL | Hours to a day | Very low — a single SQL statement |
| Streaming connectors | The source is Kafka, Kinesis, Event Hubs or a CDC feed | Seconds to minutes | Medium — connector and source configuration |
| Unity Catalog Volumes | Files are governed non-tabular data (images, video, models) rather than tabular rows | N/A | Low — managed storage path with access control |
The decision rule in one line: if the source produces files, use Auto Loader or COPY INTO. If the source produces events, use a streaming connector. A file-based pipeline can never beat the latency of a message bus, because the bus delivers the event and the file pipeline still has to wait for the file to be closed, written and listed.
COPY INTO deserves more attention than it gets, because for a lot of estates it is the right answer:
COPY INTO bronze.raw_events
FROM 's3://warehouse/raw/events/'
FILEFORMAT = JSON
PATTERN = 'events-*.json'
It is idempotent by default — it tracks what it has loaded and skips those files — and it needs no schema location, no checkpoint and no streaming cluster. If your requirement is “the data is available by 6am”, COPY INTO is simpler and cheaper than Auto Loader in a streaming configuration. Our AWS Data Engineering Training covers the equivalent serverless batch patterns on the AWS side.
For events rather than files, the managed streaming connectors cover Kafka, Kinesis and Event Hubs, and the database CDC connectors cover change data capture from operational databases.
Media files and device telemetry
This is where the honest answer matters, because “ingest video streams” is two completely different problems wearing the same words.
Problem one: media files landing as objects. Cameras, encoding farms, CDN transfers and content pipelines produce files — segments, clips, thumbnails, metadata sidecars, manifests. These arrive continuously and land in storage. For this, Auto Loader is exactly right: it picks up each new segment or metadata file within minutes, and the objects themselves live in a governed location.
media_assets = (
spark.readStream
.format("cloudFiles")
.option("cloudFiles.format", "json")
.option("cloudFiles.schemaLocation", "s3://warehouse/schema/media_manifests")
.load("s3://warehouse/raw/media/manifests/")
.select("asset_id", "asset_uri", "duration_seconds", "captured_at", "codec")
)
What you are doing here is ingesting the manifest and metadata, not the video bytes. The video stays in storage — ideally in a Unity Catalog Volume, which gives path-level access control and cloud-native credential passthrough, so the bytes never need to be copied into the lakehouse.
The processing of video content itself — decoding frames, running inference over them — is a separate workload, and it belongs in a job that reads the asset URIs from the Delta table and works on a GPU runtime or a serving endpoint. Ingesting and processing are two different problems with two different costs.
Problem two: live telemetry from devices. Phones, meters, sensors and vehicles produce events at high frequency, and those events are events, not files. The architecture is:
Devices → message bus → Structured Streaming → Delta (bronze) → Silver → Gold
The bus options are Kafka, Amazon Kinesis, Azure Event Hubs or Google Cloud Pub/Sub. The Structured Streaming documentation covers the incremental model and the checkpointing that gives exactly-once processing, and the Kafka integration guide covers the connector setup.
A hybrid often turns out to be right: telemetry arrives over the bus for the seconds-level path, and a periodic full snapshot lands as a file and goes through Auto Loader for the reconciliation path. The bus keeps the dashboards live; the file path keeps the data correct.
Governance: what Unity Catalog changes
Auto Loader can write to a Unity Catalog managed table, an external table, or a Delta path outside the catalogue. The choice determines who can read the data and whether lineage is captured.
With a managed table, Databricks owns the storage, the table is registered in Unity Catalog, and access is controlled by catalogue grants and row filters. The Unity Catalog documentation covers the model, and the access control reference covers the privilege hierarchy.
With an external table, the data stays where it is — in the bucket, in ADLS, wherever the producer put it — and the table is a pointer plus metadata. That matters when the producer owns the data lifecycle.
Either way, the storage location itself must be declared as an external location in Unity Catalog so that the credential path is governed rather than ambient. This is a common gap in estates that grew quickly: an ingestion job writing through a service principal with broad storage access works fine until an auditor asks who else can read that path.
Adoption and demand: the numbers behind the topic
Retrievable rather than assumed, pulled on 3 November 2026:
| Signal | Value | Source |
|---|---|---|
| Apache Iceberg GitHub stars | 9,385 | github.com/apache/iceberg |
| Apache Iceberg forks | 3,638 | github.com/apache/iceberg |
| PySpark downloads, last month | 47,831,780 | pypistats — pyspark |
| PySpark downloads, last week | 11,479,386 | pypistats — pyspark |
Iceberg is the relevant number here because open table formats are the direction both file ingestion and cross-engine sharing are moving. A lakehouse that ingests with Auto Loader and stores in Delta or Iceberg is not picking a vendor format — it is picking an open one, which is what makes the next migration possible.
For search interest rather than adoption volume, the reproducible check is a Google Trends comparison of Databricks, Auto Loader and Delta Lake in India, which you can run for your own region and window.
How to read these numbers
Download and repository counts come from PyPI’s public statistics endpoint and the GitHub API, retrieved on 3 November 2026. Both are raw counts that move daily — read them as direction, not as a fixed fact. Nothing in this article is a benchmark we ran ourselves; where we cite our own benchmarking work, it is linked with its methodology.
Key terms
| Term | What it means in practice |
|---|---|
| Auto Loader | Managed incremental ingestion of new files from cloud object storage into Delta. |
| Checkpoint | The persistent record of processed files. Deleting it means re-ingesting everything. |
| Schema location | Where the inferred schema is stored. Must be outside the data location. |
cloudFiles |
The file-source format behind Auto Loader, and the option that controls schema behaviour. |
| File notification mode | Event-driven ingestion driven by storage events instead of prefix listing. |
| Rescue data column | Where malformed rows are preserved instead of failing the batch. |
availableNow |
Trigger that processes the currently available files and then stops. |
| COPY INTO | Idempotent SQL batch load. Simpler than Auto Loader, not as fast. |
| Streaming connector | Ingestion from Kafka, Kinesis or Event Hubs. For events, not files. |
| Unity Catalog Volume | Governed non-tabular storage path for files such as images, video and models. |
Frequently asked questions
What is Databricks Auto Loader and what does it do?
Auto Loader is a Databricks-managed feature that ingests new files from cloud object storage into a Delta table incrementally. It tracks already-processed files in a checkpoint, infers and evolves the schema of incoming data, and handles malformed rows by preserving them in a rescue column rather than failing the batch. It exists to remove the three problems that kill naive ingestion: full re-reads, duplicate processing and schema drift.
What is the difference between Auto Loader and COPY INTO?
COPY INTO is a single SQL statement that loads files in a scheduled batch and is idempotent by default. Auto Loader is a streaming-capable ingestion pipeline with a checkpoint and automatic schema evolution, which picks up new files within minutes rather than on a schedule. Use COPY INTO when a daily load is enough and simplicity matters; use Auto Loader when files arrive continuously or the schema changes without warning.
How does Auto Loader avoid processing the same file twice?
It records processed files in a checkpoint, which by default lives at the checkpointLocation path you specify. On each run, the already-ingested set is compared against what is available and only new files are processed. Two warnings: never write checkpoints into the data location, and never delete the checkpoint path unless a full re-ingest is genuinely intended — deleting it means every file is treated as new.
Does Auto Loader work for real-time streaming?
Auto Loader is for files, and it delivers near-real-time ingestion of those files — typically within minutes of arrival. For genuine event streams from Kafka, Kinesis or Event Hubs, use a streaming connector with Structured Streaming instead, which processes events as they arrive rather than waiting for files to land and be discovered.
How does Auto Loader handle schema changes?
By default it infers the schema from the first files, stores it at the schemaLocation, and then evolves it as new columns appear — with schemaChangeMode set to addNewColumns, new fields are added to the target table automatically. Rows that do not conform are diverted to the rescue data column so they are preserved rather than dropped. You can also choose stricter modes that reject the change, which is the right setting when a silent schema change would corrupt downstream models.
Is Auto Loader expensive?
The cost driver is per-file overhead rather than per-byte, so a prefix of hundreds of thousands of tiny files costs far more than the same data in larger files. Directory listing mode also incurs storage list requests proportional to the total file count in the prefix, which is why large prefixes should use file notification mode. Our Cloud Infrastructure Cost Benchmark 2026 covers the FinOps measurement approach behind those decisions.
Can Auto Loader read video files?
It can track the arrival of media files and their metadata, and the media itself can be held in a governed Unity Catalog Volume. But Auto Loader ingests tabular records, not video content — decoding frames and running inference over them is a separate workload that reads the asset URIs and runs on a GPU runtime. Treating “ingest the video” and “process the video” as one task is how pipelines end up with enormous, useless bronze tables.
How is Auto Loader different from a traditional ETL script?
A traditional script has no memory of what it processed, so it re-reads everything and relies on downstream deduplication to stay correct. Auto Loader makes the ingestion itself incremental and exactly-once through its checkpoint, and it handles schema drift as a first-class case rather than an exception. The work that remains is the transformation and the business logic — which is where it belongs.
Where to take this next
Ingestion is where a lakehouse either earns trust or loses it. Get it right and everything downstream — the medallion layers, the aggregates, the AI workloads — can assume that bronze is complete and consistent. Get it wrong and every downstream team builds a workaround for your pipeline.
The Databricks Training course runs 12 weeks and 72 hours across eight modules, and the ingestion module covers Auto Loader, COPY INTO, streaming connectors, checkpoint management and schema evolution hands-on, followed by Delta Lake in depth, Unity Catalog governance, and a capstone that assembles a governed pipeline with a runbook and a cost estimate. For the vendor-neutral view of the same architecture — SQL, Python, Spark, Airflow, Kafka, Delta Lake, medallion modelling — the Data Engineering Training programme spans 16 weeks and 96 hours.
Our own benchmarking work on these platforms, with reproducible scripts and published methodology, is in the Snowflake vs Databricks benchmark and the State of AWS Data Engineering 2026 report.
References
- Databricks — ingest data from cloud object storage
- Databricks — Auto Loader
- Databricks — COPY INTO
- Databricks — Lakeflow Connect managed streaming connectors
- Databricks — Lakeflow Connect database CDC connectors
- Databricks — Structured Streaming concepts
- Databricks — Kafka integration
- Databricks — Unity Catalog overview
- Databricks — Unity Catalog access control
- Databricks — Unity Catalog Volumes
- Databricks — job schedules and triggers
- Apache Iceberg — documentation
- SkilBrill — Snowflake vs Databricks benchmark
