What's new, 8 min read, updated 13 October 2026

Polars 2.0: streaming by default, spill to disk and what breaks

Released on 6 October 2026: streaming is now the default, big queries can spill to disk, and row order is no longer guaranteed unless you ask. Here is what changes.

PythonWhat's new
All guides and cheat sheets

Polars, the fast DataFrame library many analysts now use alongside or instead of pandas, released version 2.0 on 6 October 2026. It is a major version for a good reason: the engine that runs your queries has changed, and with it a few assumptions about row order and data types. Here is what is new, what can quietly change your results, and how to upgrade safely.

The streaming engine is now the default

When you collect() a lazy query, Polars now uses its streaming engine, which processes data in batches instead of loading everything into memory at once. For most queries, that means much lower memory use and better speed, with no code changes.

Python
import polars as pl

revenue = (
    pl.scan_parquet("sales/*.parquet")
      .filter(pl.col("year") == 2026)
      .group_by("region")
      .agg(pl.col("revenue").sum())
      .collect()          # runs on the streaming engine in Polars 2.0
)

Eager operations on a DataFrame still run in memory as before.

Queries bigger than your RAM: spill to disk

Out-of-core processing is now on by default: when memory use passes about 80% of your RAM, Polars starts writing intermediate data to disk instead of crashing. Sorts, window functions and many expressions can spill today; joins and group-bys are planned. For analysts working on a laptop, this means fewer "out of memory" surprises on large files.

The change to watch: row order

This is the one that can silently change results. The streaming engine does not guarantee row order for joins, group_by and unpivot. If your code relies on rows coming out in the original order, ask for it explicitly:

Python
# Keep the left table's row order in a join
result = orders.join(customers, on="customer_id", how="left",
                     maintain_order="left").collect()

# Or simply sort when order matters for the output
result = lf.unpivot(pl.selectors.numeric(), index="month").collect().sort("month")

A good rule: if a report, export or test depends on order, add an explicit sort() at the end.

Stricter types: errors up front

Polars 2.0 prefers to fail early. In the team's words, errors should appear "up-front, not 20 minutes into a pipeline". A few common examples from the upgrade guide:

Python
# Casting text to a date now raises: parse it instead
pl.Series(["2026-10-13"]).str.to_date()

# Gluing tables side by side with different heights now raises
pl.concat([df1, df2], how="horizontal_extend")   # pads with nulls, as before

# Comparing integers with floats in is_in() no longer converts silently
pl.Series([1]).is_in(pl.Series([1.99]).cast(pl.Int64))

You can call collect_schema() on a lazy query to check column names and types without running it, which catches many problems in seconds.

New: a Map type and first-class SQL

  • Map columns: key-value data, common in Parquet files and APIs, now has its own pl.Map type with expressions such as pl.col("scores").map.get("math"), map.keys() and map.values().
  • SQL as a first-class interface: SQL queries get the same optimiser improvements, including join reordering and smarter filters, so writing SQL in Polars is now a serious option.
Python
pl.sql("""
    SELECT region, SUM(revenue) AS revenue
    FROM sales
    GROUP BY region
""").collect()

Other breaking changes

  • read_csv(columns=[...]) now returns columns in the order you asked for.
  • explode() on an empty list now produces no row; pass empty_as_null=True for the old behaviour.
  • LazyFrame.profile() and the old DataFrame interchange protocol were removed; use to_arrow() or to_pandas() to move data between libraries.
  • Parquet map columns now load as the new Map type.

How to upgrade

  • Run your tests on Polars 2.0 in a branch, and look first at anything that depends on row order.
  • If something breaks and you need time, switch back to the in-memory engine for one query with lf.collect(engine="in-memory"), or for the whole process with pl.Config.set_engine_affinity("in-memory").
  • Read the official upgrade guide for the full list of type changes before switching production pipelines.

Polars or pandas? Both just had major releases. See Upgrading to pandas 3.0, and for SQL on files, DuckDB 2.0: what's coming.

Sources: the Polars blog post "Release of Polars 2.0" (6 October 2026) and the official Polars 2.0 upgrade guide. Benchmarks published by the Polars team compare it favourably with DuckDB and DataFusion; as always, test on your own data.

Alessandro Ecclesie AgazziWritten by Alessandro Ecclesie Agazzi, analytics engineer in London. Updated 13 October 2026. About me