COPY INTO

kept in this browser

COPY INTO is the idempotent SQL command that loads files from object storage into a Delta table, remembering what it already loaded and running from a SQL warehouse.

Checked against the Databricks documentation on · history

On this page12

What it is

COPY INTO is a SQL command that reads files from cloud object storage (S3, ADLS, GCS) or from a Unity Catalog volume and appends them to a Delta table. Its key property: it is idempotent. It keeps track of the files it has already loaded and, when you rerun it on the same path, skips the ones it has seen. You can schedule it every hour with no risk of duplicates.

Why it exists

An INSERT INTO ... SELECT * FROM read_files(...) works exactly once: on the second run it reloads everything. Before COPY INTO you had to maintain a ledger of processed files by hand. COPY INTO folds that ledger into the target table and exposes it as pure SQL, runnable from a notebook, from a SQL task in a job (see Lakeflow Jobs, what a job is), or directly from a SQL warehouse, with no checkpoint and no Python code.

How it works

Core syntax:

COPY INTO <catalog>.<schema>.<table>
FROM '<path>'
FILEFORMAT = <format>
[FILES = ('a.csv', 'b.csv') | PATTERN = '<glob>']
[FORMAT_OPTIONS (...)]
[COPY_OPTIONS (...)];

FILEFORMAT

Accepted formats are CSV, JSON, AVRO, ORC, PARQUET, TEXT, BINARYFILE. Source files can also be compressed.

FILES and PATTERN

FILES lists up to 1000 explicit file names; PATTERN takes a glob (*.json, 2026-0[1-6]/*.parquet, {orders,resi}_*.csv). They are mutually exclusive.

FORMAT_OPTIONS

Options passed to the format reader, the same ones the Spark data sources accept: for CSV header, delimiter, inferSchema; for JSON multiLine; for all formats rescuedDataColumn, which stores values that don’t fit the schema in a dedicated column (see Semi-structured data: JSON, nested data, VARIANT).

COPY_OPTIONS

Options that govern the command’s behavior:

OptionDefaultEffect
mergeSchemafalseadds new columns found in the files to the table (schema evolution)
forcefalsedisables idempotency: reloads every file, including those already processed

Watch out for the double mergeSchema: in FORMAT_OPTIONS it asks the reader to merge the schemas of the files with each other; in COPY_OPTIONS it evolves the target table. A load with a changing schema often needs both.

Transformations on the fly

Instead of a bare path you can put a SELECT over the path: that lets you cast columns, add current_timestamp() or _metadata.file_path, filter rows, all in a single command.

Schemaless table

You can create a table without a schema with CREATE TABLE IF NOT EXISTS t; and let the first COPY INTO with mergeSchema = 'true' define it. This requires Databricks Runtime 11.3 LTS or later. On a schemaless table, INSERT INTO and MERGE INTO don’t work until the first COPY INTO has populated it.

Example

Incremental load of order CSVs from a volume, with schema evolution and audit columns:

CREATE TABLE IF NOT EXISTS shop.bronze.orders;

COPY INTO shop.bronze.orders
FROM (
  SELECT *, current_timestamp() AS ingested_at, _metadata.file_path AS source_file
  FROM '/Volumes/shop/landing/orders/'
)
FILEFORMAT = CSV
PATTERN = '*.csv'
FORMAT_OPTIONS ('header' = 'true', 'inferSchema' = 'true', 'mergeSchema' = 'true')
COPY_OPTIONS ('mergeSchema' = 'true');

The same command from Python, if you’re in a notebook:

spark.sql("""
  COPY INTO shop.bronze.orders
  FROM '/Volumes/shop/landing/orders/'
  FILEFORMAT = CSV
  PATTERN = '*.csv'
  FORMAT_OPTIONS ('header' = 'true', 'inferSchema' = 'true', 'mergeSchema' = 'true')
  COPY_OPTIONS ('mergeSchema' = 'true')
""")

Rerun an hour later, it loads only the CSVs that arrived in the meantime. If a file was corrupt, fix it and reload it with COPY_OPTIONS ('force' = 'true'), narrowing the set with FILES.

COPY INTO or Auto Loader?

COPY INTOAuto Loader
InterfaceSQL commandcloudFiles stream (Python or SQL streaming table)
Statetracked in the tableRocksDB checkpoint
Scaleup to thousands of files per directorymillions of files, file notification
Schema evolutionmergeSchemaconfigurable modes, _rescued_data
File discoverylisting on every runincremental listing or notifications
Whenfew files, pure SQL, warehousehigh volumes, streaming or pipelines

The docs are explicit: for directories that contain a very large number of files, prefer Auto Loader.

Common mistakes

  • Expecting COPY INTO to reload a modified file with the same name: the file counts as already loaded and gets skipped. You need force or a new file name.
  • Using force = 'true' in a scheduled job “just to be safe”: it duplicates data on every run.
  • Forgetting header = 'true' on CSVs: the first row becomes a record.
  • Putting mergeSchema only in FORMAT_OPTIONS and wondering why the table doesn’t evolve.
  • Running COPY INTO concurrently on the same set of files from two jobs: it only works on disjoint file sets.

Check yourself

3 questions on what this page says. Pick an answer, then check it.

  1. 1The same COPY INTO command runs every hour on one folder. What happens to files that an earlier run already loaded?
    Show the answer

    A. They are skipped, so a rerun adds no duplicates

    COPY INTO is idempotent: it keeps track of the files it has loaded and skips them on later runs, which makes scheduled reruns safe.

  2. 2A load sets mergeSchema = 'true' only in FORMAT_OPTIONS, and the target table never gains the new columns found in the files. Why?
    Show the answer

    B. In FORMAT_OPTIONS it only merges the files' schemas with each other; evolving the table needs it in COPY_OPTIONS

    The option means two things: in FORMAT_OPTIONS it asks the reader to merge file schemas, in COPY_OPTIONS it evolves the target table. A changing-schema load often needs both.

    Read the section again
  3. 3A corrupt file was loaded, and you fixed it without changing its name. How do you load the fixed version?
    Show the answer

    D. Rerun with force = 'true' in COPY_OPTIONS, limited to that file with FILES

    A file with the same name counts as already loaded and is skipped. force turns idempotency off, and FILES narrows the run so other files are not duplicated.

    Read the section again

Where this sits

Resources

3All resources
Report a problem with this page
What kind of problem?

Reports about "COPY INTO" go to the maintainer, not to a public thread.

Suggest a resource
What kind?

Nothing appears on the site automatically. A person reads every suggestion, checks the link and writes the note that goes with it.