Release highlights: 1.27
Breaking changes
workspaceextra removed and dev tooling split into a plugin. Theworkspaceextra is gone. Installmarimo,pyarrow,ibis,fastmcp, and other dependencies directly.dlt dashboard,dlt pipeline ... show, anddlt pipeline ... mcpnow requirepip install dlt[hub], anddlt aimoved todlthub ai(#3929).
Yield Polars frames from resources
Resources can now yield polars.DataFrame and polars.LazyFrame objects directly, with no manual conversion (#3837). dlt auto-detects them and routes them through the Arrow extraction path, collecting LazyFrames first, so Parquet loading and schema inference apply. Install with pip install dlt[polars].
import dlt
import polars as pl
@dlt.resource
def orders():
yield pl.DataFrame({"order_id": [1, 2, 3], "amount": [100.0, 200.0, 300.0]})
pipeline = dlt.pipeline("orders", destination="duckdb")
pipeline.run(orders())
Load into Databricks via Zerobus
The Databricks destination can now ingest into Delta tables through the Zerobus SDK instead of COPY INTO. Set insert_api="zerobus" on the destination or per resource with databricks_adapter, for the append write disposition (#3904). Configure the endpoint under [destination.databricks.zerobus].
import dlt
from dlt.destinations.adapters import databricks_adapter
@dlt.resource(write_disposition="append")
def events():
yield from [{"id": 1}, {"id": 2}]
databricks_adapter(events, insert_api="zerobus")
pipeline = dlt.pipeline("events", destination="databricks")
pipeline.run(events())
Incremental filters on datasets
Relation.incremental() turns a dlt.sources.incremental cursor into a WHERE clause, so you read only rows in the cursor window straight from a dataset (#3889). Pass a column or table.column cursor path. A dotted path auto-joins the referenced table. It also works via dataset.table(..., incremental=...).
import dlt
from dlt.common.pendulum import pendulum
pipeline = dlt.pipeline("events", destination="duckdb")
dataset = pipeline.dataset()
cursor = dlt.sources.incremental(
"created_at",
initial_value=pendulum.datetime(2026, 1, 1, tz="UTC"),
end_value=pendulum.datetime(2026, 2, 1, tz="UTC"),
)
rows = dataset.table("events", incremental=cursor).fetchall()
Auto-accept CLI confirmations with -y
A global -y/--yes flag auto-accepts every confirm() prompt, so destructive commands like pipeline drop and sync run unattended in CI (#3910). It differs from --non-interactive, which only picks prompt defaults and so skips actions that default to no.
dlt -y pipeline chess_pipeline drop players_games
Empty data no longer truncates the destination table
Running merge with empty data after a replace on an incremental resource could silently truncate the destination table, a regression introduced in 1.27.0. 1.27.2 reverts the change (#3999). Anyone on 1.27.0 or 1.27.1 should upgrade.
Cleaner float to decimal coercion
Coercing a Python float into a decimal or wei column now converts through str() first, so 34.7 stores as 34.7 instead of a long IEEE 754 tail like 34.700000000000003 (#3928). For exact values, keep source data as Decimal or strings rather than floats.
Shout-out to new contributors
Big thanks to our newest contributors:
Full release notes