// the find
narwhals-dev/narwhals
Lightweight and extensible compatibility layer between dataframe libraries!
Narwhals is an abstraction layer that lets you write one function and have it work against pandas, Polars, DuckDB, PyArrow, PySpark, Dask, and more. It's aimed at library authors who don't want to maintain separate code paths per dataframe backend. End users of those libraries never touch Narwhals directly.
Zero runtime dependencies — it only imports what you pass in, so adopting it doesn't bloat your library's install footprint. The API is the Polars subset, which is a good choice: Polars expressions are composable and explicit, unlike pandas' chaotic surface area. 100% branch coverage tested against nightly pandas and Polars builds is a real commitment, not a vanity badge — it means breakage from upstream gets caught before it ships. The stable/v1 and stable/v2 namespaces with a documented backwards compatibility policy are exactly what a library author needs before depending on something.
The 'lazy-only support' tier for DuckDB, PySpark, Dask, and Ibis is a meaningful limitation that the README buries — you can't use Series operations or eager collect on those backends, which forces you to split your code paths anyway for anything non-trivial. The API is a subset of Polars, which means if you need something Polars supports but Narwhals hasn't exposed yet, you're stuck filing an issue and waiting; the extension plugin system exists but it's not an escape hatch for arbitrary operations. Pandas index handling is described as supported without 'getting in the way', but in practice pandas MultiIndex and named indexes introduce subtle behavioral differences that Narwhals papers over rather than eliminates — worth reading the concepts docs before assuming it just works.