full-loading page does not say which replace strategies each destination supports (test, ignore) - #4336
full-loading page does not say which replace strategies each destination supports (test, ignore)#4336ShreyasGS wants to merge 4 commits into
Conversation
…stination supports (test, ignore)
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | bf70e43 | Commit Preview URL Branch Preview URL |
Aug 10 2026, 10:11 PM |
|
|
||
| `supported_replace_strategies` lists everything the destination may use. `resolve_replace_strategy` applies the per-table narrowing and returns the strategy that will actually be used for that table, or `None` if the strategy you passed is not available for it. The table format is what narrows the list today: on the `filesystem` and `athena` destinations, tables with the `delta` or `iceberg` table format are always replaced with `insert-from-staging`, and all other tables only with `truncate-and-insert`. | ||
|
|
||
| If you request a strategy that is not available, dlt does not fall back to another one: the load step fails with an error naming the table, and no data is loaded. Pick a strategy from the supported list, or change the table format if that is what restricts the choice. A destination may also reject a strategy for reasons it can only check against the live database. ClickHouse `staging-optimized`, for example, requires the Atomic or Shared database engine. |
There was a problem hiding this comment.
name the exception this raises, and say which destinations support only
truncate-and-insert — lance is the one I know of
|
Named the exception and added the destinations restricted to On the exception: I ran it rather than reading it off the source, because the code has two error paths and only one of them is reachable. On the destinations: |
| dlt implements three different strategies for doing a full load on your table: `truncate-and-insert`, `insert-from-staging`, and `staging-optimized`. The exact behavior of these strategies can also vary between the available destinations. | ||
|
|
||
| You can select a strategy with a setting in your `config.toml` file. If you do not select a strategy, dlt will default to `truncate-and-insert`. | ||
| You can select a strategy with a setting in your `config.toml` file. If you do not select a strategy, dlt uses the first strategy that the destination supports for the table being loaded, which is `truncate-and-insert` wherever it is available. |
There was a problem hiding this comment.
add a line showing how to set replace_strategy per resource or per pipeline, if
that is possible at all — the toml block only shows the global setting
There was a problem hiding this comment.
Per pipeline is possible, per resource is not. Added a second toml block with [destination.duckdb] and [github_issues.destination], a snippet passing replace_strategy to the destination factory, and a sentence saying there is no per-resource setting. Confirmed in the checkout: replace_strategy lives on DestinationClientDwhConfiguration (dlt/common/destination/client.py:313); dlt.resource(replace_strategy=...) raises TypeError: resource() got an unexpected keyword argument 'replace_strategy'. With that config.toml, a pipeline named github_issues on duckdb resolved to staging-optimized while another pipeline resolved to insert-from-staging from the [destination.duckdb] section.
|
Added the missing scoping to the "Choosing the correct replace strategy" section: a To answer the question directly: per pipeline is possible, per resource is not. |
|
/revise the new section names the destinations that support truncate-and-insert |
|
Added the grouping asked for, as a three-item list at the end of Which strategies your destination supports. Your guess was right as far as it went but the group is larger: I enumerated |
Documentation for #4334: full-loading page does not say which replace strategies each destination supports (test, ignore)
Closes #4334
What changed
Edited the existing page
general-usage/full-loading.md. The sidebar is unchanged.Its runnable code is in
full-loading-snippets.py, which pytest executed during verification.Sections: Performing a full load, Choosing the correct replace strategy for your full load.
How this was checked
All claims checked against the checkout (dlt installed from source in docs/.venv).
Source read:
dlt/common/destination/utils.py::resolve_replace_strategy— appliescapabilities.replace_strategies_selector(if any) tocapabilities.supported_replace_strategies, returnsNonewhen the list is empty or whenrequired_strategyis not in it, otherwiserequired_strategy or supported_replace_strategies[0]. So the default is the first entry of the (possibly narrowed) list, not a hardcodedtruncate-and-insert.dlt/destinations/utils.py::verify_schema_replace_dispositionraisesSchemaCorruptedException("Requested replace strategy ... not available for table ...");dlt/destinations/job_client_impl.py::prepare_load_tableasserts on the same condition. Either way the load step fails — there is no fallback.dlt/destinations/impl/filesystem/factory.py::filesystem_replace_strategies_selectoranddlt/destinations/impl/athena/factory.py::athena_replace_strategies_selector:delta/icebergtables →["insert-from-staging"], all other tables →["truncate-and-insert"].dlt/destinations/impl/clickhouse/clickhouse.py::_verify_database_supports_exchangeraisesDestinationTerminalExceptionunless the database engine is Atomic or Shared.Capabilities dumped from the branch (
<factory>().capabilities().supported_replace_strategies), showingtruncate-and-insertis always first where present: postgres/bigquery/snowflake/mssql/databricks/clickhouse have all three; duckdb, motherduck, redshift, synapse, dremio, sqlalchemy, athena, filesystem havetruncate-and-insert+insert-from-staging; qdrant, weaviate, lancedb onlytruncate-and-insert.Snippet run under the docs pytest setup → 1 passed, printing
black --check,mypy --config-file ../pyproject.tomlandflake8 --max-line-length=200on the snippet file all pass.Failure behaviour reproduced: with
DESTINATION__REPLACE_STRATEGY=staging-optimizedon duckdb,pipeline.run([{"id": 1}], table_name="items", write_disposition="replace")raisedPipelineStepFailedatstep=loadand theitemstable did not exist afterwards (Catalog Error: Table with name items does not exist!). The same request onfilesystemwithinsert-from-stagingfor a regular table also failed at the load step.What I could not confirm
The user-visible exception for an unsupported strategy differs by code path: in my duckdb and filesystem runs the loader hit the
AssertionErrorinprepare_load_table(via the truncate filter indlt/load/utils.py::init_client, which runs beforejob_client.verify_schema) rather than theSchemaCorruptedExceptionfromverify_schema_replace_dispositionthat the issue quotes. Because the message a user sees is not stable between those two, the page says only that the load step fails with an error naming the table. That ordering may be worth a look on the engineering side.The snippet uses
dlt.common.destination.utils.resolve_replace_strategyandPreparedTableSchema, which are not part of the documented public API (the loader andtests/load/test_job_client.pyuse the same function). If you would rather not point users at them, the destination-levelcaps.supported_replace_strategiesline alone still answers most of the question.I did not verify the
staging-optimizedbehaviour of any warehouse destination end to end (no credentials), so nothing in the existing per-destination bullet list was changed.Draft opened by agentic-docs from the labelled issue.
Verification ran dlt's linters, the link and anchor checker and the style rules over this page. Its examples are in
full-loading-snippets.py, which pytest executed here and runs again in dlt's CI.