Releases: dlt-hub/dlt
Releases · dlt-hub/dlt
Release list
1.29.1
dlt 1.29.1 Release Notes
Core Library
- Add
instancerequirement spec for jobs (#4262 @tetelio) — Jobs can now declare runner instance requirements viarequire.instance(an openDict[str, Any], e.g.{"size": "medium"}). The legacymachinekey is deprecated — it still works and serializes, but now emits aDltDeprecationWarningpointing toinstance. Fully backward compatible. - Fix: use case-sensitive identifiers in sqlglot schema (#4269 @rudolfix) — sqlglot 30.13.0 began case-folding identifiers in more cases; case folding is now explicitly prevented when building the sqlglot schema.
- Fix: preserve REST paginator stop conditions on
has_more=true(#4227 @mattfaltyn) — An API returninghas_more=truecan no longer re-enable a paginator that already hit a stop condition (maximum_offset/maximum_page, response total, or a missing cursor), preventing requests past a hard limit or without a valid cursor. Fixes #4225. - Fix: handle non-scalar total in REST range paginator (#4186 @anxkhn) — A
total_pathresolving to a JSON object or array now raises the paginator's clear "not an integer"ValueErrorinstead of escaping as an opaqueTypeError. - Fix: allow JWT auth without scopes (#4235 @mattfaltyn) —
OAuthJWTAuthwith the defaultscopes=Noneno longer raisesTypeError; thescopeclaim is omitted when no scopes are configured. Fixes #4234. - Fix: pass load id column name to
remove_columnsas a sequence (#4241 @chuenchen309) —add_dlt_load_id_columnno longer dropsRecordBatchcolumns whose name is a substring of_dlt_load_id(e.g.id,load), which previously produced silent NULLs or a crash. Fixes #4240.
Docs
- Replace dead playground link in README with the dlt + Hugging Face marimo notebook demo (#4267 @elviskahoro)
- Remove an outdated IP address from the docs (#4238 @VioletM)
Chores
- fix(ci): preserve dependency resolution across test jobs (#4264 @Travior) — Propagates matrix resolution settings via
UV_SYNC_ARGS, preventsuv runfrom resyncing prepared CI environments (UV_NO_SYNC), bumps the GitPython minimum, and keeps the SQLGlot compatibility test green across versions. - test(ci): rerun remote destinations on transient connection errors (#4243 @burnash) — Widens
pytest-rerunfailuresfilters so transient ODBC/Azure SQL and Databricks connection errors get retried instead of failing the run, while benign assertion failures still fail fast.
New Contributors
- @chuenchen309 made their first contribution in #4241
- @anxkhn made their first contribution in #4186
1.29.0
dlt 1.29.0 Release Notes
Highlights
- ClickHouse
staging-optimizedreplace strategy (#3927 @filipesilva) — ClickHouse now supports thestaging-optimizedreplace strategy, performing atomic table swaps viaEXCHANGE TABLESso a full replace is instantaneous and never leaves the destination in a half-loaded state. - AWS Secret Manager config provider (#4162 @rudolfix) — dlt can now resolve config and secrets directly from AWS Secret Manager, matching the existing Google Secret Manager provider. Also stops re-creating the Google secrets client on every lookup.
- Explicit joins in
Relation.join()(#3868 @burnash) — The dataset relation API gains explicit join support, giving you control over join conditions when composing relations. - Cross-destination join compatibility (#3905 @Travior) — Destination configs now expose a
physical_location()accessor andcan_join_withrules, so dlt knows when relations that live on different destinations (or datasets) can actually be joined together.
Core Library
Features
- BigQuery atomic replace (#4130 @oystersuki) — New opt-in
enable_atomic_replaceconfig flag makes thetruncate-and-insertstrategy do a single-job, metadata-preservingWRITE_TRUNCATE_DATAload from GCS staging, giving BigQuery an atomic, transactional full replace. - DuckDB SQLAlchemy destination (#4161 @rudolfix) — Fully tests and fixes the SQLAlchemy destination running on DuckDB.
- Expose Parquet compression codec (#4183 @Travior) — Configure the Parquet compression codec via
DATA_WRITER__COMPRESSIONorParquetFormatConfiguration(compression=...). - Cross-batch schema evolution in
ArrowToParquetWriter(#3896 @AyushPatel101) — Safe Arrow type promotions (e.g.float32 → float64) now work across flush batches instead of crashing once data spans multiple batches. - Additional Redshift COPY options (#4088 @timH6502) — New Redshift config to append extra options (e.g.
FILLRECORD) to the generatedCOPYcommand for staged loads. - Cross-destination join compatibility (#3905 @Travior) — See Highlights.
- Disable
dlt→dlthubcommand proxying in workspace context (#4037 @rudolfix) — Instead of silently running adlthubcommand,dltnow shows a note and points to the correctdlthubcounterpart, avoiding misleading behavior.
Fixes
- Fix: Normalize crash on empty Arrow tables with
add_dlt_id(#4187 @nizar-zerrad) — Adding_dlt_idto an empty Arrow table no longer fails withArrowInvalid. - Fix: correct table/resource metric aggregation (#4155 @tetelio) — Writer metrics are now aggregated correctly when jobs for the same table interleave across normalize workers or file rotation (previously undercounted
items_count). - Fix: Airflow parallel staging truncation (#4079 @DRACULA1729) — Auto-disables staging truncation for
decompose="parallel"/parallel-isolatedruns so concurrent tasks no longer truncate each other's staging files. - Fix: move misplaced merge subqueries to post-qualify (#4169 @rudolfix) — Corrects merge SQL generation where pre-qualify subquery collapse could not work correctly.
- Fix: switch replace strategy correctly (#4164 @rudolfix)
- Fix: use truncate mechanism for empty "replace" tables (#4153 @rudolfix) — Empty "replace" resources are truncated via load-package state rather than empty files, avoiding hint side-effects.
- Fix: use empty files to truncate top-level tables (#4168 @rudolfix) — Partially reverts #4153 for optimized replace strategies, where truncation happens upfront rather than inside the job transaction.
- Fix: reuse job client when truncating staging dataset (#4207 @rudolfix)
- Fix: keep the pipeline selector when no pipeline is selected (#4096 @lis365b) — Dashboard keeps the pipeline dropdown visible and shows a clearer empty-state message when the selection is cleared.
- Fix: logging more frequent than
log_period(#3962 @cbility) — Stops resetting the log timer on every counter update, so logs respect the configuredlog_period. - Bump jsonpath-ng and improve test coverage (#4105 @Travior) — Upgrades to
jsonpath-ng1.8.0, dropping the archivedplytransitive dependency flagged by security scanners (CVE).
Docs
- Add Tigris to S3-compatible storage options for the filesystem destination (#4166 @davidmyriel)
- Add secrets management page to dltHub docs (#4124 @ShreyasGS)
- Add "Orchestrate with dltHub" cookbook entry (#4077 @ShreyasGS)
- Add Slack and email notifications guide (#4081 @ShreyasGS)
- Add playground workspace page (#4150 @AstrakhantsevaAA)
- Add playground destination page (#4148 @AstrakhantsevaAA)
- Clarify soft deletes description for MSSQL source (#4165 @AstrakhantsevaAA)
Chores
- Add git commit-message rule, hook, and
/commitskill (#4098 @lis365b) — Claude Code tooling to keep commit messages Conventional-Commit clean (no footers/emojis). - Refactor ibis handover — create ibis backend on the
Destinationfactory (#4170 @rudolfix) - Relax dlthub-client deps (#4202 @rudolfix)
- Fix Windows path for griffe tests (#4104 @rudolfix)
New Contributors
- @filipesilva made their first contribution in #3927
- @cbility made their first contribution in #3962
- @DRACULA1729 made their first contribution in #4079
- @oystersuki made their first contribution in #4130
- @davidmyriel made their first contribution in #4166
- @nizar-zerrad made their first contribution in #4187
1.28.2
1.28.1
dlt 1.28.1 Release Notes
Python 3.9 EOL
- Dropped Python 3.9 support (#4074 @Travior) — Python 3.9 reached end-of-life on 2025-10-31. dlt no longer tests against or advertises support for 3.9. The
ruff/mypytarget versions were bumped accordingly. Users still on 3.9 must upgrade to 3.10+ to use this release.
Highlights
- Dataset browser shown by default in the dltHub dashboard (#4068 @lis365b) — The dashboard now opens directly on the dataset browser (no entry page, no toggle), auto-selecting the most recently used pipeline. Empty-state copy was made generic so it reads correctly both locally and in the dltHub runtime. Resolves product_backlog#153.
Core Library
- Dataset browser by default in the dashboard (#4068 @lis365b) — see Highlights.
- Fix: connectorx temporal-column precision on newer connectorx (#3996 @tetelio) — Newer connectorx returns timestamps as
timestamp[ns]and times astime64[ns](via thearrow_streamreturn type) instead ofdate64(ms). dlt now normalizes all connectorx temporal columns to microsecond precision (the renamedcast_connectorx_temporal_columns), truncating ns→us losslessly since source DBs carry no nanoseconds. - Fix: ISO week/year in
detect_datetime_formatso week-date cursors round-trip (#4061 @yashs33244) — Week-date formats (YYYY-Www) were detected as%Y-W%W, which disagrees with ISO weeks at year boundaries."2026-W01"parsed to 2025-12-29 and re-rendered as"2025-W52", silently corrupting saved incremental cursors. Now emits%G-W%V/%G-W%V-%u. - Fix: remove
0x0characters from postgres INSERT strings (#4086 @rudolfix) — Postgres escaping allowed null (0x0) characters through; they are now stripped in the escape function. INSERT statements are also split by\nonly. - Fix: metadata caching in
sql_database(#4067 @rudolfix) — User-passedmetadatais now correctly consulted for cached tables in both eager and deferred reflection. Fixes #4066. - Fix: cap codex skill descriptions at 1024 chars on
ai init(#4072 @lis365b) — Codex silently drops skills whosedescriptionfrontmatter exceeds 1024 chars. The Codex install path now truncates the installedSKILL.mddescription to the cap (with a warning) so workbench skills likedlthub-routerload correctly.
Docs
- Add EU static egress IPs for the dltHub platform (#4085 @tetelio)
- Add EU proxy/egress IPs for the dltHub platform (#4084 @tetelio)
- Recommend
dlthub-initvsdlthub-startconsistently in onboarding docs (#4080 @bjoaquinc) - Clean up hub getting-started/installation wording and remove outdated commands (#4070 @ShreyasGS)
- Document the managed playground destination (#4075 @tetelio)
Chores
- Faster CI testing + Python 3.14 on CI (#3996 @tetelio) — Splits monolithic
test_common.ymlinto 27 parallel focused jobs (3 per OS/Python combo) so wall-clock is roughlymax(suite)instead ofsum(suites), moves runners toblacksmith-*variants, and enables Python 3.14 in CI (running the full suite, with 3.14-gated depssnowflake-connector-python>=4.4.0andcffi>=1.18). Also includes job/workflow renames; one functional reduction —lance_s3non-essential tests now run only on full-suite triggers. - Fix: pin airflow smoke-test installs with the airflow constraints file (#4069 @Travior) — Adds a script that fetches the latest airflow version and builds the matching constraint file, as airflow recommends for application installs.
New Contributors
- @yashs33244 made their first contribution in #4061
1.28.0
dlt 1.28.0 Release Notes
Breaking Changes
refresh="drop_data"on Delta and persistent-catalog Iceberg no longer frees storage (#4051 @rudolfix) — Truncation is now a transactional delete that keeps the table, schema, version history, and data files (retained for time travel untilvacuum). Previously the files were deleted. This corrects prior erroneous behavior, but pipelines relying ondrop_datato reclaim disk space will no longer see storage freed without an explicitvacuum.replacenow fully truncates empty and orphaned tables (#4010 @rudolfix) — Tables belonging to areplaceresource that receive no data in a run (including nested tables, dynamic-name and variant tables) are now consistently truncated. Previously these tables could be left orphaned with stale rows surviving the reload, leaving the dataset in an inconsistent state. Pipelines that implicitly relied on that leftover data will now see those tables emptied.
Highlights
- Lance destination write optimizations (#4051 @rudolfix) — Namespace/session pooling shares one
LanceNamespace+lance.Sessionacross job clients; atomic single-commit-per-table writes uncommitted fragments in parallel and commits them in one version (Append/Overwrite/upsert).replaceis now a singleOverwritecommit so readers never see a partially-replaced table, and the namespace pool rebuilds handles on credential rotation to avoidExpiredTokenon long loads. Also fixes #3800 (Iceberg409 Table already existsafterdrop_sources). - Reliable
replace/refreshtruncation (#4010 @rudolfix) —replaceresources now consistently truncate all participating tables even when a load carries no data (nested tables, dynamic names, variants included), anddrop_datarefresh truncates correctly onappendand survives non-existent tables.refreshis now the recommended way to do a full refresh — thereplaceswitch is deprecated. Also fixes #3998 and #4017. - Configurable CSV encoding (#4045 @AstrakhantsevaAA) — New
write_encodingoption lets you choose the encoding of CSV files dlt writes (defaultutf-8), e.g.utf-8-sigfor Excel BOM orlatin-1/cp1252for legacy importers. Set via[normalize.data_writer] write_encoding="latin-1". - Refreshable cloud credentials for long-running loads (#4056 @tderk) — Default credential-chain credentials are now passed to external consumers (fsspec, rust crates, fileio) consistently and as refreshable where supported, instead of being frozen once. Fixes
ExpiredTokenfailures on long-held connections (#4003).
Core Library
Features
- Prune duplicate deps from launcher groups (#4044 @rudolfix) — Deps already present in user requirements are eliminated; numpy/pandas removed from rows→arrow conversion and dashboard deps. Row conversion uses a pure-arrow fast path (up to ~2x faster) or a Python
zippath as good as pandas. - CDN marimo launcher (#4049 @tetelio) — Serve marimo frontend assets from jsDelivr CDN via configurable
--asset-url. Launcher path resolution usesfind_specinstead ofimport_moduleso notebooks aren't executed beforemarimo run/streamlit run(~1–1.5s faster port readiness).
Fixes
- Fix: duckdb refreshes
credential_chainsecrets to survive temp-token expiry (#4021 @0ywfe) — AddsREFRESH autoso long-heldsql_clientconnections no longer die withExpiredTokenonce temporary AWS tokens rotate. Fixes #3987. - Bump duckdb to 1.5.3, ducklake to 1.0 (#4055 @rudolfix)
- Fix:
Retry-After: 0no longer triggers an immediate retry loop (#4043 @AstrakhantsevaAA) — Values ≤ 0 are treated as no actionable hint, letting tenacity's exponential backoff take over. Fixes #4036. - Fix: clickhouse insert file quoting (#4018 @rudolfix) — Also bumps the driver version. Fixes #4014.
- Fix: incremental merge truncates destination on no-data runs (#4000 @burnash) — Port of the 1.27.2 hotfix (#3998) to devel with a regression test.
- Fix: databricks emits foreign key only when
create_indexesis enabled (#4011 @burnash) — Avoids Unity CatalogUC_REFERENTIAL_CONSTRAINT_DOES_NOT_EXISTfailures when the matching primary/unique key isn't created. - Fix: DuckLake DuckDB-backed catalog attach incorrectly applied
META_TYPE 'sqlite'(#3871 @Analect) — Splits the duckdb/sqlite branch so aduckdb:///catalog.duckdbcatalog URI attaches cleanly instead of failing onPRAGMA journal_mode=WAL. - Fix: mssql ingests parquet row-groups individually to bound ADBC driver memory (#3947 @wtfashwin) — Prevents OOM on parquet files larger than available memory. Closes #3915.
Docs
- Streamlit cookbook entry + Cookbook sidebar restructure into dlt / dlthub subcategories (#4050 @ShreyasGS)
- Langfuse cookbook (#4038 @zilto)
- Apply review feedback on dltHub docs (datasets, data-quality API) (#3975 @ShreyasGS)
- Remove memory warning from delta-rs docs now that the upstream issue is resolved (#4060 @tetelio)
- Restore orphaned content after docs restructuring + add orphan-detection lint step (#4028 @rudolfix)
- Restore orphaned docs on master (#4029 @rudolfix)
- High-contrast dltHub docs button (#4040 @zilto)
- Fix outdated dashboard description (commands + broken link) (#4053 @AstrakhantsevaAA)
- Escape
__in generated CLI docs to prevent markdown bold (#3993 @burnash) - Escape characters to correct
__deployment__.pyfile name in CLI docs (#3988 @nuetu) - Fix typo in egress IPs list (#3992 @tetelio)
- Remove the Star Wars gif (#3994 @AstrakhantsevaAA)
Chores
- Retry flaky databricks and motherduck remote tests (#4046 @burnash) — Adds
pytest-rerunfailures, scoped to just those two transient destinations via--only-rerun. - Fix Arrow string-width assumptions in pandas 3 CI (#4025 @Travior) — Updates deltalake/filesystem reader tests for pandas 3's Arrow-backed string columns. Fixes #4024.
- Increase marimo cell re-render timeout in dashboard tests (#3991 @burnash) — Bumps 15s → 30s to stop
test_multi_schema_selectionflaking on slow CI. - master → devel merge after hotfixes (#4019 @rudolfix)
New Contributors
1.27.2
1.27.0
dlt 1.27.0 Release Notes
Breaking Changes
workspaceextra removed anddlthubcommand split out (#3929 @rudolfix) — Theworkspaceextra is gone; users should installmarimo,pyarrow,ibis,fastmcp, and other dependencies directly. Part of dev tooling moved to a plugin:dlt dashboard,dlt pipeline ... show,dlt pipeline ... mcpnow requirepip install dlt[hub].dlt aiwas moved todlthub ai.
Highlights
- Native Polars DataFrame and LazyFrame support in resources (#3837 @AyushPatel101) — Polars DataFrames and LazyFrames can now be yielded directly from
@dlt.resourcewithout manual conversion. Auto-detected and routed through the Arrow extraction pipeline; LazyFrames are auto-collected before conversion. - Databricks Zerobus loading (#3904 @jorritsandbrink) — New
databricks_adapter(my_resource, insert_api="zerobus")enables loading via the Databricks Zerobus SDK into Delta tables. API mirrorsbigquery_adapter; supported forappendwrite disposition. - Incremental filtering for
dlt.Relation(#3889 @burnash) — Apply incremental filters directly ondlt.Relation, enabling efficient incremental reads from datasets. dlthubcommand split (#3929 @rudolfix) — Reorganizes_workspacemodules and splits dev tooling (dashboard,mcp,ai) into a dedicateddlt[hub]plugin. See Breaking Changes above.
Core Library
- Native Polars DataFrame / LazyFrame support (#3837 @AyushPatel101) — See Highlights.
- Databricks Zerobus loading (#3904 @jorritsandbrink) — See Highlights.
- Incremental filtering for
dlt.Relation(#3889 @burnash) — See Highlights. dlthubcommand split (#3929 @rudolfix) — See Highlights / Breaking Changes.lancedestination REST Namespace support (experimental) (#3908 @jorritsandbrink) — Adds experimental REST Namespace support to thelancedestination, currently only validated against an ephemeral in-memory Lance REST Namespace proxy.-y/--yesflag to bypass non-interactive prompts (#3910 @anuunchin) — New flag auto-accepts allconfirm()prompts via a dedicatedALWAYS_CONFIRMflag inecho.py, without leaking intoprompt()ortext_input(). Resolves #3592.- Control dashboard section opening from URL (#3686 @djudjuu) — Lets external tools / agents pre-open a specific section of the dashboard via URL, useful for guiding users to particular pipeline state.
- Fix: Pydantic annotation metadata handling across 2.10–2.13 (#3863 @Travior) — Restores discriminated
RootModelhandling and preserves root-levelAnnotated[...]metadata after Pydantic 2.13 moved the discriminator offroot_field.annotation. - Fix: correctly materialize empty tables for multi-table resources (#3901 @anuunchin) — Tracks empty tables (not resources) so multi empty-table materialization works correctly. Resolves #3840.
- Fix:
scd2unmapped insert for nested tables (#3812 @deschman) — Generates an explicit column list (excluding SCD2from/tometadata) for the staging-to-destination insert, fixingDATATYPE_MISMATCHerrors on Spark/Databricks ANSI mode when schemas drift. Fixes #3811. - Fix(clickhouse): replica-safe merge delete temp tables (#3824 @RedZapdos123) — Detects the destination table engine and uses
ReplicatedMergeTree/SharedMergeTreefor merge delete temp tables, preventing duplicates on replicated/shared MergeTree deployments. Closes #3797. - Fix(databricks): replace deprecated
_user_agent_entry(#3935 @xodn348) — SwitchesDatabricksCredentials.to_connector_params()to the non-prefixeduser_agent_entry, silencing the deprecation warning printed on every connection. Closes #3934. - Fix:
with_load_idbreaking on non-root sibling branches (#3878 @Travior) - Fix: schema naming convention respects
max_lengthparam (#3826 @aditypan) — Removes spurious length appending in schema naming whenmax_lengthis provided. Fixes #3816. - Fix: propagate
dataset_nameto job metrics in load step (#3808 @rudolfix)
Docs
- Docs structure overhaul (#3884 @zilto) — Reorganizes the documentation site structure.
- OSS / paid split documentation (#3745 @VioletM)
- Cookbook: Arize Phoenix example (#3914 @zilto)
- Improve docs around
joinusage (#3902 @Travior) - Misc docs fixes (#3909 @zilto)
Chores
- CI from fork (#3897 @anuunchin) — Splits CI so secret-requiring tests run via a new
fork_tests_with_secrets.ymlworkflow gated by theci from forklabel and a maintainer approval in thefork-cienvironment. Resolves #3850. - Workspace tests setup fixes + CLI docs refresh (#3948 @rudolfix)
- Scope
fruit_pipelinefixture to module to avoid duckdb lock race (#3932 @burnash) — Stabilizes the dashboard e2e suite.
New Contributors
1.26.0
dlt 1.26.0 Release Notes
Breaking Changes
- Incremental external scheduler now raises instead of silently warning (#3877 @rudolfix) — Untyped/non-coercible cursor values now raise
JoinSchedulerError; missing intervals raiseExternalSchedulerNotAvailable. Resources withallow_external_schedulers=Truethat previously fell back to dlt state will now fail. This is a bugfix that corrects previously incorrect behavior.
Highlights
dlt.Relation.join(...)(#3590 @Travior) — Adds ajoin()method ondlt.Relationbased on the normalizer and table references, enabling fluent relational composition over datasets.- Extended Snowflake query tags (#3759 @Travior) — Snowflake query tagging is extended beyond load jobs to broader dlt operations: storage setup, schema/state reads, schema updates, load execution, load completion, and table drops.
TJobQueryTagsis generalized toTQueryTagswith a newoperationfield (with a compatibility export). - Time interval context for incrementals (#3877 @rudolfix) — New
dlt.current.interval()returns the active(start, end)interval orNone, backed by an injectableTimeIntervalContextwith optionalallow_external_schedulersoverride and auto-detection from env vars / Airflow.
Core Library
dlt.Relation.join(...)(#3590 @Travior) — see Highlights.- Extended Snowflake query tags beyond load jobs (#3759 @Travior) — see Highlights.
- Time interval context for incrementals (#3877 @rudolfix) — see Highlights.
- Destination-aware incremental SQL filter (#3877 @rudolfix) — New
dlt/extract/incremental/sql.py(to_sqlglot_filter) honorstimestamp_precision,supports_tz_aware_datetime_in_cast, and sqlite quirks; works on bound and unbound incrementals. start_valuepersisted in incremental state (#3877 @rudolfix) — Only written when rows actually arrive, so it is no longer advanced silently on empty runs.uuid_to_stringPyArrow fast path (#3877 @rudolfix) — Numpy-vectorized with a pure-Python fallback; pyarrow ≥ 24arrow.uuidextension arrays are coerced to canonical strings, and UUID columns under pyarrow < 24 also take the fast path.- Custom metrics emitted even when a resource produces no data (#3877 @rudolfix) —
dlt.current.resource_metrics()counters are no longer dropped when every item is filtered out. - TypedDict validator honors
NotRequired[T](#3877 @rudolfix) — Via__required_keys__. - sqlglot
"dremio"dialect literal (#3877 @rudolfix) — Added toTSqlGlotDialect. - Opt-in naming-convention check in
Schema.unify_schemas()(#3898 @burnash) — The naming-convention check inSchema.unify_schemas()is now opt-in; also drops the max_length tests workaround. - Fix(clickhouse): correct metadata sort keys to avoid full scans (#3851 @anuunchin) — Resolves #3806 by correcting metadata sort keys so ClickHouse no longer performs full scans.
- Fix(pyarrow): preserve string encoding for UUID columns under pyarrow 24+ (#3894 @burnash) — Fixes #3893 so UUID columns keep their string encoding under pyarrow 24+.
- Fix: clearer error from
dlt.attach()when pipeline cannot be restored (#3890 @bjoaquinc) — RewritesCannotRestorePipelineExceptionmessages to name required inputs, show a concretedlt.attach(...)example, and offerdlt.dataset()as a lighter alternative; suppresses a redundant inner exception in tracebacks. - Fix: closed-pipe race in
iter_std(#3877 @rudolfix) — Reader threads swallowValueError/OSErrorand always close the queue. - Fix: active profile shown in
ConfigFieldMissingException(#3877 @rudolfix)
Docs
- Improved dashboard docs (#3484 @VioletM)
- Updated documentation for pg_replication (#3900 @dat-a-man) — Adds an "Alternative: CDC with Debezium" section linking to the Debezium + dlt demo.
- Snowflake marketplace listing link (#3888 @kaliole)
- Quality-checker fixes to
pipeline.md(#3885 @ShreyasGS) — Tense, contractions, and grammar cleanups via Harper + Vale Google Developer Docs style. - Remove playground page and associated CI (#3883 @zilto) — Streamlines the "Getting Started" section; interactive material remains on Google Colab and marimo molab.
- Pydantic Logfire export example (#3882 @zilto)
New Contributors
- @bjoaquinc made their first contribution in #3890
1.25.0
dlt 1.25.0 Release Notes
Breaking Changes
- Multischema datasets (#3770 @burnash) — Datasets can now hold multiple schemas. The main benefit is to be able to see tables from all source in multi-source pipelines. This is a new default behavior.
Users can pass a list of schemas todataset()method and still go back to single-schema dataset by providingpipeline.default_schemawhen creating dataset.
Highlights
lancedestination (#3810 @jorritsandbrink) — New destination for the Lance table format with optional vector embedding generation vialancedb. Supports local storage ands3/az/gs, uses the Lance Directory Namespace V2 spec, and supports branching. Complements the existinglancedbdestination (which targets LanceDB Cloud).- Multischema datasets (#3770 @burnash) — See Breaking Changes above. Enables sidecar schemas (e.g. data-quality quarantine tables) to live alongside the primary schema in a single dataset.
- Improved progress and load metrics (#3768 @rudolfix) — Load metrics now persist across restarts, normalizer metrics are updated via update files, and the follow-up job graph is saved into the trace. Closes the long-standing #853.
Core Library
lancedestination (#3810 @jorritsandbrink) — See Highlights.- Multischema datasets (#3770 @burnash) — See Highlights.
- Improved progress and load metrics (#3768 @rudolfix) — See Highlights.
ducklake:metadata_schemaATTACH option (#3763 @sangwookWoo) — Addsmetadata_schematoDuckLakeCredentialsso the DuckLake metadata schema can be configured independently fromducklake_name.- Fix: preserve credential chain in AWS credentials (#3798 @rudolfix) — Default credential mixing applied correctly, STS scoped to Databricks only. Closes #3115.
- Fix: replay state transitions after crash (#3767 @rudolfix) — Writes a pending state-transition marker right after the DB commit so an interrupted load no longer leaves the load package in an inconsistent state.
- Fix: create all eligible tables on staging dataset (#3765 @rudolfix) — Closes #2862.
- Fix: normalize pool workers skip
__main__in orchestrators (#3784 @rudolfix) — Closes #3586. - Fix(clickhouse): lightweight DELETE for single-table merge (#3783 @rudolfix) — Removes the
_dlt_idrequirement when merging arrow tables without nested tables on ClickHouse. - Fix(clickhouse): pass
aws_session_tokento stagings3()table function (#3769 @anuunchin) — Temporary AWS credentials now work for ClickHouse staging. - Fix: avoid leaking PUA markers in nested fields (#3760 @serl) — Fixes Pydantic nested-model PUA-marker leak. Closes #3755.
- Fix: deepcopy paginator in child resource (#3779 @anuunchin) — Prevents paginator state corruption across child-resource invocations. Closes #3772.
- Fix: honor explicit non-utf8 encoding in filesystem
read_csv(#3743 @biefan) — File is opened with the requested encoding so SFTP/paramiko stacks no longer pre-decode as UTF-8. - Fix: don't filter out trace steps with exceptions (#3843 @anuunchin) —
trace.asdict()now retains pipelines that fail in the sync step before extract. - Fix: check duckdb version when installing lance extension (#3773 @zilto) — Handles the
lanceextension promotion to built-in in duckdb 1.5. - Fix: transient Windows file-lock
PermissionErrorinrename_tree(#3853 @burnash) — Resolves intermittent Windows CI failures during normalize→loaded rename. - Fix: deprecation warnings across supported package versions (#3831 @anuunchin) — Closes #3785, #3807, #3787, #3794.
Docs
- Cookbook section (#3860 @zilto) — Tested examples moved to a dedicated top-level tab; dlt tab added for navigation back; UI cleanups.
- Same-domain docs button (#3859 @zilto) — Avoids full page reload when navigating.
- Explore-and-transform page (#3782 @hibajamal) — New page covering data-exploration and transformations workbench toolkits.
- Expand handover-to-other-toolkits section (#3737 @njaltran) — Expands data-exploration toolkit coverage in
llm-native-workflow.md. - Add EAI instructions (#3803 @kaliole)
- Update name to dlt Connector App (#3857 @kaliole) — Snowflake Native App docs renamed.
- Update source count to 8,000+ (#3830 @Pawansingh3889) — Closes #3761.
- Rename dltHub Basic tier to dltHub Pro (#3795 @elviskahoro)
- Fix outdated
hf logincommand (#3781 @julien-c)
Chores
- Move
mypyconfigs topyproject.toml(#3780 @zilto) — Partially resolves #3346. - Remove Python 3.9 from CI matrices (#3777 @zilto) — Python 3.9 reached EOL in October 2025. Resolves #3587, #3619.
- Increase Playwright timeout in e2e dashboard test (#3848 @burnash) — Matches the 15s timeout used elsewhere; reduces Windows CI flakiness.
- Silence Airflow 3.2 smoke-test log noise (#3835 @burnash) — Fixes #3834.
New Contributors
1.24.0
dlt 1.24.0 Release Notes
Breaking Changes
- Custom resource metrics now stored as tables (#3718 @rudolfix) — Incremental metrics in the trace are now represented in table format. This changes the location and structure of incremental metrics in the trace object.
Highlights
- Insert-only merge strategy (#3741 @rudolfix, based on #3372 by @OnAzart) — New
insert-onlymerge strategy that performs idempotent, key-based appending: inserts records whose primary key doesn't exist in the destination while silently skipping duplicates. No updates or deletes. Supported across all SQL destinations, Delta Lake, and Iceberg. - Parallelize all sources in Airflow (#3652 @JustinSobayo) — In
parallelandparallel-isolateddecompose modes, all source components now fan out concurrently from a shared start node. Previously the first source had to complete before others could begin, adding unnecessary wall-clock time. This release also adds basic Airflow 3 support with smoke tests. - ClickHouse ReplacingMergeTree support (#3366 @prevostc) — New
replacing_merge_treetable engine type for ClickHouse that enables native deduplication and soft deletes viadedup_sortandhard_deletecolumn hints. - Custom resource metrics as tables (#3718 @rudolfix) — Resources can now emit custom metrics that are stored as tables in the trace, enabling richer observability for pipelines.
Core Library
- Insert-only merge strategy (#3741 @rudolfix, based on #3372 by @OnAzart) — See Highlights.
- ClickHouse ReplacingMergeTree support (#3366 @prevostc) — See Highlights.
- Parallelize all sources in Airflow (#3652 @JustinSobayo) — See Highlights.
- Custom resource metrics as tables (#3718 @rudolfix) — See Highlights.
- Configurable Arrow table concatenation promote_options (#3701 @AyushPatel101) —
arrow_concat_promote_optionscan now be set to"default"or"permissive"instead of the hardcoded"none", enabling automatic type promotion when yielding multiple Arrow tables with slightly different inferred types. - Fix: CLI info/show fails on custom destinations (#3676 @anuunchin) —
dlt pipeline info/showno longer crashes withUnknownDestinationModuleon pipelines using@dlt.destination. - Fix: Primary key assignment for incremental resources (#3679 @shnhdan) — Passing
primary_key=()toIncrementalto disable deduplication is no longer silently overwritten by the resource's own primary key. - Fix: MotherDuck missing catalog validation (#3723 @YuF-9468) — Connection strings that omit the catalog/database name (e.g. bare
md:) now raise a clear configuration error instead of a confusing connection failure. - Fix: BigQuery infinite loop on internal error (#3732 @aditypan) — BigQuery jobs that encounter an internal error no longer cause an infinite retry loop.
- Fix: SCD2 column order mismatch in SQLAlchemy destinations (#3733 @anuunchin) — SCD2 validity column insert jobs now match the column order of existing tables in SQLAlchemy destinations.
- Fix: Timezone mapping in SQL timestamp datatype (#3735 @aditypan) — Timezone is now correctly set for timestamp/datetime column datatypes.
Docs
- Realistic closure-based data masking example (#3617 @veeceey) — Replaced the hardcoded example with a reusable
mask_columns()function supporting allsql_databasebackends. - Redirects for removed pages (#3688 @djudjuu)
- AI workbench license info (#3729 @lis365b)
- Minor doc fixes (#3734 @anuunchin)
Chores
- Bumps npm docs deps (#3728 @rudolfix)
- Switch lancedb example from Spotify to PodcastIndex (#3736 @Travior)
- Adds CLI docs check to docs CI workflow (#3739 @rudolfix)
- Moves render CLI docs command to a separate tool (#3740 @rudolfix)