Polars py-1.42.0 - Cloud IO and Streaming Fixes


Polars py-1.42.0 was published on June 24, 2026 for Python users of the pola-rs/polars project. The most useful change for data engineering teams is the set of cloud IO and parquet read improvements, especially bytes based concurrency control, object store DNS handling, and metadata work for multi file parquet scans.

The full release notes and downloads are on the GitHub release page.

This release gives cloud backed scans more operator visible controls. Polars now has bytes based concurrency control for cloud IO, which is a more useful limit than a raw task count when object sizes vary. That matters for pipelines that read a mix of small partition files and large fact files from object storage.

The release also adds DNS cache and shuffle behavior for cloud object_store access. That is a small line item in the notes, but it affects steady state object store traffic in long running workers. It can help avoid pinning all reads to one resolved address when the backing service has several endpoints.

There are also parquet and Delta scan changes. Polars adds a tiered multi file parquet metadata resolver, supports external object_store access for non native schemes, and can skip Delta files and parquet row groups using per field struct statistics. Those are planning and read path changes, not user interface changes. They matter when the same lazy query has to touch large partition sets and still avoid reading data that predicates already rule out.

file:// handling also gets a practical fix for percent encoded paths. That is useful for local staging areas and ingestion tests where path names are generated by another system instead of typed by a person.

SQL users get several planner changes in py-1.42.0. Polars now supports SQL implicit JOIN syntax, lowers SQL [NOT] IN (subquery) to semi/anti join plans, and fixes computed GROUP keys in SQL projections. The release also addresses join alias state leakage in SQL CTEs, which is the kind of bug that can make generated SQL behave differently after a query rewrite.

The expression surface grows with Expr.is_sorted and DataFrame.is_sorted(). Those are small APIs, but they are useful in pipeline assertions and branch decisions where sorted input controls whether a later join, window, or sink step is valid.

The optimizer side is also worth reading. The release optimizes len() and null_count comparisons, including non negative comparisons, and eliminates filters with contradictory predicates. It also improves IR sortedness detection for with_row_index and explode. These changes reduce wasted work, but they also change explain output, so teams that snapshot query plans in tests should expect some churn.

Several fixes are aimed at correctness in lazy, streaming, and sink paths. Polars fixes cross join predicates that were not applied when using sink_* functions. It also fixes a SchemaError path for lazy HConcat to sink, projection pushdown with row index ordering, and incorrect schema order for hstack in the projection pushdown optimizer.

Streaming execution gets a performance improvement for struct unnest inside list eval. The release also fixes duplicated map_elements warnings on the streaming engine and checks continuity across morsels in the AsOf join node. Those items are narrow, but they sit in parts of the engine that production ETL code tends to stress with large inputs and lazy plans.

There are smaller order and length fixes as well. Slice expressions now always observe input order, select(len()) no longer returns zero for scan_iceberg when pyiceberg is used as a reader override, and selecting expressions with slice plus length no longer gives the wrong length. Polars also keeps maintain_order on sliced unique and preserves null placement when collapsing sort.reverse() into a single sort.

The main migration signal is the deprecation of casts from string to temporal dtypes. If a pipeline parses timestamps from raw strings, stop relying on generic casts and move parsing into explicit temporal conversion paths. That makes failures easier to reason about and avoids future behavior changes when the deprecated path is removed.

There is also a new deprecation warning for .explode() calls without the empty_as_null argument. Code that depends on empty list handling should set that argument deliberately. This is the kind of warning worth fixing early because it changes row shape semantics in data cleaning code.

The release adds experimental strict mode and naive out of core spilling. Treat both as things to test under representative data volume before enabling them in shared jobs. The Kubernetes OOM documentation note in this release is also a reminder that spilling and memory policy need to be tested with real pod limits, not only on developer machines.