CLI Reference
plan
Preview what apply and load would do: every table, column, type mapping, write strategy, route and cursor. Changes nothing.
sqlload plan [SELECTOR ...] [OPTIONS]sqlload plan prints what apply and load would do:
tables to create or alter, each column’s type mapping, write strategy, route, batches and cursor.
It reads the sources’ and destinations’ catalogs and changes nothing. apply and load print the
same plan before they run. See Projects for how the three fit together.
In a Kafka exporter configuration, plan shows each topic’s table and the
objects it needs, and refuses the options below.
Selecting tables
Section titled “Selecting tables”A selector is a source name, a destination table name, or a source’s schema.table. Give
selectors positionally or with --select, and leave tables out with --exclude. With none, every
table is selected. See Selecting tables for examples.
A source’s problems, such as a refused setting or a server it can’t reach, fail only a command that selects something from it. A source that can’t list its tables also fails a command that selects a table by name, since that table could be one of its own.
Options
Section titled “Options”plan, apply and load take the same options.
| Option | Meaning |
|---|---|
SELECTOR ..., -s, --select <SELECTOR>... |
Sources or tables to select: a source name, a destination table name, or a source’s schema.table. All when none is given. |
--exclude <SELECTOR>... |
Sources or tables to leave out. Wins over --select. |
--start-cursor <VALUE> |
Read from this cursor value instead of the destination’s maximum. Typed from each table’s cursor: an integer, an RFC 3339 timestamp or a date. |
--end-cursor <VALUE> |
Read only cursor values below this one. |
--reload |
Rebuild the selected tables from the whole source, with the current columns and types. Asks first, unless --yes. Refuses postgres_cdc tables, which --resnapshot copies again; see Reloading. |
--resnapshot |
postgres_cdc sources: drop and recreate the replication slot, then copy every table again. Asks first, unless --yes. See Postgres changes. |
--follow |
load of one postgres_cdc source only: keep streaming after catching up, writing a batch every batch_interval, until --max-duration passes or Ctrl-C or SIGTERM. See Keep streaming. |
--max-duration <DURATION> |
With --follow: stop after this long, such as 10m, once the changes read so far are written. |
--yes |
Rebuild with --reload or --resnapshot without asking. Needed when not on a terminal. |
--allow-type-change-rebuild |
Allow table rebuilds that type_change_rebuild = "require_confirmation" would block. |
--concurrency <N> |
The most tables loading at once. Default: the project’s concurrency, else 4. |
--json |
Print one JSON document on standard output. For plan, the plan. For apply and load (from 0.27.0), the result: see Results as JSON. |
Reading a plan
Section titled “Reading a plan”$ sqlload planPlan ready 2 selected, 2 objects to create, 2 to loadto DuckDB local
Objects (2) sqlload apply├── raw.app__customers create table│ ├── customer_id int -> BIGINT│ ├── email text -> VARCHAR│ ├── country text -> VARCHAR│ ├── created_at timestamp_tz -> TIMESTAMP WITH TIME ZONE (stored as a UTC instant; the offset is not kept)│ └── + _sqlload_load_id, _loaded_at└── raw.app__orders create table ├── order_id int -> BIGINT ├── customer_id int -> BIGINT ├── status text -> VARCHAR ├── total decimal(12,2) -> DECIMAL(12,2) ├── updated_at timestamp_tz -> TIMESTAMP WITH TIME ZONE (stored as a UTC instant; the offset is not kept) └── + _sqlload_load_id, _loaded_at
Loads (2) sqlload load├── raw.app__customers merge (unique_key: customer_id ← {primary_key})│ ├── source postgres app public.customers│ └── route read as Arrow -> DuckDB takes Arrow└── raw.app__orders merge (unique_key: order_id ← {primary_key}) ├── source postgres app public.orders ├── route read as Arrow -> DuckDB takes Arrow └── reads updated_at: first run, everything
✓ Plan complete 2 selected, 2 objects to create, 2 to loadTables are named as they land, schema.table, and sorted by that name. A table read by cursor
says where its read starts and when it commits:
$ sqlload planPlan ready 2 selected, 2 to loadto DuckDB local
Loads (2) sqlload load├── raw.app__customers merge (unique_key: customer_id ← {primary_key})│ ├── source postgres app public.customers│ └── route read as Arrow -> DuckDB takes Arrow└── raw.app__orders merge (unique_key: order_id ← {primary_key}) ├── source postgres app public.orders ├── route read as Arrow -> DuckDB takes Arrow └── reads updated_at >= 2026-11-01 16:40:00+00 (warehouse maximum)
✓ Plan complete 2 selected, 2 to loadreads gives the cursor’s bound (>= when the bound row is read again, > when it isn’t) and
where it comes from: the warehouse maximum, minus any lookback, --start-cursor, or a logged
state. commits shows when the read doesn’t commit the usual way.
A plan of several tables names each destination on a to line; when there are several, each
route names its destination too. It leaves out why, and the batch and schema lines most of
its tables share. Select one table to see every line, with times to the millisecond:
$ sqlload plan app__ordersPlan ready 1 selected, 1 to load
Loads (1) sqlload load└── raw.app__orders merge (unique_key: order_id ← {primary_key}) ├── source postgres app public.orders ├── route read as Arrow -> DuckDB takes Arrow ├── key order_id, the primary key the source reports (unique_key = "{primary_key}", sqlload.toml:21) ├── reads updated_at >= 2026-11-01 16:40:00.000+00 (warehouse maximum) ├── columns 5 └── commits about every 1 GB, in updated_at order (an index leads with it, NULLs first), between distinct values
✓ Plan complete 1 selected, 1 to loadOn a terminal, plan shows Planning checking sources, 1 of 3 done while it reads catalogs, and
clears it when the plan prints.
| Section | Lists |
|---|---|
Objects |
Tables apply creates or alters: each column as its portable type -> the warehouse type, then in brackets what that type loses, if anything (from 0.29.0; for an array, the array’s own loss, then its elements’ after elements:), added and widened columns, with the same note from 0.31.0, excluded and masked columns. |
Loads |
Each table load loads, with its write strategy, and lines for source, key, reads, commits, files, schema, route, why, batch and note. A plan of one table also shows columns (how many, and under naming = "dlt" the names it changes) and checks, and key names the sqlload.toml line that sets unique_key. |
Skipped |
Tables left out on purpose, with the reason: a files table with no new file (up to date: 0 new of 3 files in drop/orders/ (csv)), or one left out by skip_tables_with_columns or new_tables = "skip". load reads nothing for them. |
Errors |
Tables that can’t load as configured, with a short headline, the reason and the fix. A source that can’t be read is one item, with what it holds up under blocks. |
Warnings |
Tables that load, but slower or with less than you might expect. |
A table under Errors is left out; the others still run, and the command exits 1.