https://narwhals-dev.github.io/narwhals/
Lightweight and extensible compatibility layer between dataframe libraries!
https://narwhals-dev.github.io/narwhals/
cudf dask duckdb ibis pandas polars pyarrow pyspark
Last synced: 3 months ago
JSON representation
Lightweight and extensible compatibility layer between dataframe libraries!
- Host: GitHub
- URL: https://narwhals-dev.github.io/narwhals/
- Owner: narwhals-dev
- License: mit
- Created: 2024-02-19T17:51:14.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-07-15T20:49:31.000Z (3 months ago)
- Last Synced: 2025-07-16T06:39:33.204Z (3 months ago)
- Topics: cudf, dask, duckdb, ibis, pandas, polars, pyarrow, pyspark
- Language: Python
- Homepage: https://narwhals-dev.github.io/narwhals/
- Size: 10.7 MB
- Stars: 1,176
- Watchers: 15
- Forks: 156
- Open Issues: 169
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
- Code of conduct: .github/CODE_OF_CONDUCT.md
- Security: docs/security.md
Awesome Lists containing this project
README
# Narwhals
![]()
[](https://badge.fury.io/py/narwhals)
[](https://pepy.tech/project/narwhals)
[](https://peps.python.org/pep-0740/)
[](https://pypi.org/project/narwhals)Extremely lightweight and extensible compatibility layer between dataframe libraries!
- **Full API support**: cuDF, Modin, pandas, Polars, PyArrow.
- **Lazy-only support**: Dask, DuckDB, Ibis, PySpark, SQLFrame. Work in progress: Daft.Seamlessly support all, without depending on any!
- ✅ **Just use** [a subset of **the Polars API**](https://narwhals-dev.github.io/narwhals/api-reference/), no need to learn anything new
- ✅ **Zero dependencies**, Narwhals only uses what
the user passes in so your library can stay lightweight
- ✅ Separate **lazy** and eager APIs, use **expressions**
- ✅ Support pandas' complicated type system and index, without
either getting in the way
- ✅ **100% branch coverage**, tested against pandas and Polars nightly builds
- ✅ **Negligible overhead**, see [overhead](https://narwhals-dev.github.io/narwhals/overhead/)
- ✅ Let your IDE help you thanks to **full static typing**, see [typing](https://narwhals-dev.github.io/narwhals/api-reference/typing/)
- ✅ **Perfect backwards compatibility policy**,
see [stable api](https://narwhals-dev.github.io/narwhals/backcompat/) for how to opt-inGet started!
- [Read the documentation](https://narwhals-dev.github.io/narwhals/)
- [Chat with us on Discord!](https://discord.gg/V3PqtB4VA4)
- [Join our community call](https://calendar.google.com/calendar/embed?src=27ff6dc5f598c1d94c1f6e627a1aaae680e2fac88f848bda1f2c7946ae74d5ab%40group.calendar.google.com)
- [Read the contributing guide](https://github.com/narwhals-dev/narwhals/blob/main/CONTRIBUTING.md)Table of contents
- [Narwhals](#narwhals)
- [Installation](#installation)
- [Usage](#usage)
- [Example](#example)
- [Scope](#scope)
- [Roadmap](#roadmap)
- [Used by](#used-by)
- [Sponsors and institutional partners](#sponsors-and-institutional-partners)
- [Appears on](#appears-on)
- [Why "Narwhals"?](#why-narwhals)## Installation
- pip (recommended, as it's the most up-to-date)
```
pip install narwhals
```
- conda-forge (also fine, but the latest version may take longer to appear)
```
conda install -c conda-forge narwhals
```## Usage
There are three steps to writing dataframe-agnostic code using Narwhals:
1. use `narwhals.from_native` to wrap a pandas/Polars/Modin/cuDF/PyArrow
DataFrame/LazyFrame in a Narwhals class
2. use the [subset of the Polars API supported by Narwhals](https://narwhals-dev.github.io/narwhals/api-reference/)
3. use `narwhals.to_native` to return an object to the user in its original
dataframe flavour. For example:- if you started with pandas, you'll get pandas back
- if you started with Polars, you'll get Polars back
- if you started with Modin, you'll get Modin back (and compute will be distributed)
- if you started with cuDF, you'll get cuDF back (and compute will happen on GPU)
- if you started with PyArrow, you'll get PyArrow back
![]()
## Example
Narwhals allows you to define dataframe-agnostic functions. For example:
```python
import narwhals as nw
from narwhals.typing import IntoFrameTdef agnostic_function(
df_native: IntoFrameT,
date_column: str,
price_column: str,
) -> IntoFrameT:
return (
nw.from_native(df_native)
.group_by(nw.col(date_column).dt.truncate("1mo"))
.agg(nw.col(price_column).mean())
.sort(date_column)
.to_native()
)
```You can then pass `pandas.DataFrame`, `polars.DataFrame`, `polars.LazyFrame`, `duckdb.DuckDBPyRelation`,
`pyspark.sql.DataFrame`, `pyarrow.Table`, and more, to `agnostic_function`. In each case, no additional
dependencies will be required, and computation will stay native to the input library:```python
import pandas as pd
import polars as pl
from datetime import datetimedata = {
"date": [datetime(2020, 1, 1), datetime(2020, 1, 8), datetime(2020, 2, 3)],
"price": [1, 4, 3],
}
print("pandas result:")
print(agnostic_function(pd.DataFrame(data), "date", "price"))
print()
print("Polars result:")
print(agnostic_function(pl.DataFrame(data), "date", "price"))
``````terminal
pandas result:
date price
0 2020-01-01 2.5
1 2020-02-01 3.0Polars result:
shape: (2, 2)
┌─────────────────────┬───────┐
│ date ┆ price │
│ --- ┆ --- │
│ datetime[μs] ┆ f64 │
╞═════════════════════╪═══════╡
│ 2020-01-01 00:00:00 ┆ 2.5 │
│ 2020-02-01 00:00:00 ┆ 3.0 │
└─────────────────────┴───────┘
```See the [tutorial](https://narwhals-dev.github.io/narwhals/basics/dataframe/) for several examples!
## Scope
- Do you maintain a dataframe-consuming library?
- Do you have a specific Polars function in mind that you would like Narwhals to have in order to make your work easier?If you said yes to both, we'd love to hear from you!
## Roadmap
See [roadmap discussion on GitHub](https://github.com/narwhals-dev/narwhals/discussions/1370)
for an up-to-date plan of future work.## Used by
Join the party!
- [altair](https://github.com/vega/altair/)
- [bokeh](https://github.com/bokeh/bokeh)
- [darts](https://github.com/unit8co/darts)
- [formulaic](https://github.com/matthewwardrop/formulaic)
- [hierarchicalforecast](https://github.com/Nixtla/hierarchicalforecast)
- [marimo](https://github.com/marimo-team/marimo)
- [metalearners](https://github.com/Quantco/metalearners)
- [panel-graphic-walker](https://github.com/panel-extensions/panel-graphic-walker)
- [plotly](https://plotly.com)
- [pointblank](https://github.com/posit-dev/pointblank)
- [pymarginaleffects](https://github.com/vincentarelbundock/pymarginaleffects)
- [py-shiny](https://github.com/posit-dev/py-shiny)
- [rio](https://github.com/rio-labs/rio)
- [scikit-lego](https://github.com/koaning/scikit-lego)
- [scikit-playtime](https://github.com/koaning/scikit-playtime)
- [tabmat](https://github.com/Quantco/tabmat)
- [tea-tasting](https://github.com/e10v/tea-tasting)
- [timebasedcv](https://github.com/FBruzzesi/timebasedcv)
- [tubular](https://github.com/lvgig/tubular)
- [Validoopsie](https://github.com/akmalsoliev/Validoopsie)
- [vegafusion](https://github.com/vega/vegafusion)
- [wimsey](https://github.com/benrutter/wimsey)Feel free to add your project to the list if it's missing, and/or
[chat with us on Discord](https://discord.gg/V3PqtB4VA4) if you'd like any support.## Sponsors and institutional partners
Narwhals is 100% independent, community-driven, and community-owned.
We are extremely grateful to the following organisations for having
provided some funding / development time:- [Quansight Labs](https://labs.quansight.org)
- [Quansight Futures](https://www.qi.ventures)
- [OpenTeams](https://www.openteams.com)
- [POSSEE initiative](https://possee.org)
- [BYU-Idaho](https://www.byui.edu)If you contribute to Narwhals on your organization's time, please let us know. We'd be happy to add your employer
to this list!## Appears on
Narwhals has been featured in several talks, podcasts, and blog posts:
- [Talk Python to me Podcast](https://youtu.be/FSH7BZ0tuE0)
Ahoy, Narwhals are bridging the data science APIs- [Python Bytes Podcast](https://www.youtube.com/live/N7w_ESVW40I?si=y-wN1uCsAuJOKlOT&t=382)
Episode 402, topic #2- [Super Data Science: ML & AI Podcast](https://www.youtube.com/watch?v=TeG4U8R0U8U)
Narwhals: For Pandas-to-Polars DataFrame Compatibility- [Sample Space Podcast | probabl](https://youtu.be/8hYdq4sWbbQ?si=WG0QP1CZ6gkFf18b)
How Narwhals has many end users ... that never use it directly. - Marco Gorelli- [The Real Python Podcast](https://www.youtube.com/watch?v=w5DFZbFYzCM)
Narwhals: Expanding DataFrame Compatibility Between Libraries- [Pycon Lithuania](https://www.youtube.com/watch?v=-mdx7Cn6_6E)
Marco Gorelli - DataFrame interoperatiblity - what's been achieved, and what comes next?- [Pycon Italy](https://www.youtube.com/watch?v=3IqUli9XsmQ)
How you can write a dataframe-agnostic library - Marco Gorelli- [Polars Blog Post](https://pola.rs/posts/lightweight_plotting/)
Polars has a new lightweight plotting backend- [Quansight Labs blog post (w/ Scikit-Lego)](https://labs.quansight.org/blog/scikit-lego-narwhals)
How Narwhals and scikit-lego came together to achieve dataframe-agnosticism## Why "Narwhals"?
[Coz they are so awesome](https://youtu.be/ykwqXuMPsoc?si=A-i8LdR38teYsos4).
Thanks to [Olha Urdeichuk](https://www.fiverr.com/olhaurdeichuk) for the illustration!