Skip to content

Installation and quick start

Installation

Narwhals requires Python 3.10+ and has no required dependencies: it only ever uses the dataframe libraries you pass into it.

Pick the workflow that matches how you manage your project's dependencies.

If you're starting a new project with uv, add Narwhals to it with:

uv add narwhals

This will create a virtual environment (if one doesn't already exist), add narwhals to your pyproject.toml, and update uv.lock.

To install Narwhals into an existing virtual environment without touching pyproject.toml, use:

uv pip install narwhals

First, create and activate a Python 3.10+ virtual environment, then run:

python -m pip install narwhals

Unlike uv add or poetry add, pip install does not touch pyproject.toml. If you're working on a project, you'll need to record the dependency there yourself.

From within a Poetry project, run:

poetry add narwhals

This will add narwhals to your pyproject.toml and update poetry.lock.

Installing with extras

Narwhals exposes optional extras that pull in a specific backend at a version known to be compatible. These are convenience pins, not requirements: if you already have the backend installed (or want to manage its version yourself), you can skip them.

Available extras include pandas, polars, pyarrow, modin, dask, duckdb, ibis, pyspark, pyspark-connect, sqlframe, sql, and cudf (Linux only). For the authoritative list, see [project.optional-dependencies] in pyproject.toml.

Specify one or more extras in square brackets, for example:

uv add "narwhals[polars,pyarrow]"
python -m pip install "narwhals[polars,pyarrow]"
poetry add "narwhals[polars,pyarrow]"

Library authors: prefer keeping backends out of your direct dependencies

uv add "narwhals[polars,pyarrow]" adds the extras to [project.dependencies].

If you publish your project, every consumer is then forced to install polars and pyarrow, which defeats Narwhals' "support all, depend on none" design.

If you're building a library (rather than an application), keep narwhals as your runtime dependency and pin the backends only for development:

uv add narwhals
uv add --group dev "narwhals[polars,pyarrow]"
poetry add narwhals
poetry add --group dev "narwhals[polars,pyarrow]"

Dependency groups are not shipped in your distribution metadata, so consumers receive only narwhals and bring their own backend.

Alternatively, re-expose the backends as your library's own optional extras, so consumers opt in explicitly (e.g. pip install your-library[polars]):

[project.optional-dependencies]
polars = ["narwhals[polars]"]
pyarrow = ["narwhals[pyarrow]"]

Verifying the installation

To verify the installation, start the Python REPL and execute:

import narwhals

print(narwhals.__version__)
2.22.1

If you see the version number, then the installation was successful!

Quick start

Optional companion libraries

Narwhals has no required dataframe dependencies, but to follow along with the examples below you'll want at least one of:

Simple example

Create a Python file t.py with the following content:

from __future__ import annotations

import pandas as pd
import polars as pl
import pyarrow as pa
import narwhals as nw
from narwhals.typing import IntoFrame


def agnostic_get_columns(df_native: IntoFrame) -> list[str]:
    df = nw.from_native(df_native)
    column_names = df.columns
    return column_names


data = {"a": [1, 2, 3], "b": [4, 5, 6]}
df_pandas = pd.DataFrame(data)
df_polars = pl.DataFrame(data)
table_pa = pa.table(data)

print("pandas output")
print(agnostic_get_columns(df_pandas))

print("Polars output")
print(agnostic_get_columns(df_polars))

print("PyArrow output")
print(agnostic_get_columns(table_pa))
pandas output
['a', 'b']
Polars output
['a', 'b']
PyArrow output
['a', 'b']

If you run python t.py then your output should look like the above.

Running with uv (no install needed)

If you have uv, you can skip the environment setup entirely by declaring inline script dependencies at the top of t.py:

# /// script
# dependencies = ["narwhals[pandas,polars,pyarrow]"]
# ///

Then run it with uv run t.py.

This is the simplest possible example of a dataframe-agnostic function - as we'll soon see, we can do much more advanced things.

Let's learn about what you just did, and what Narwhals can do for you!

Info

These examples are using pandas, Polars, and PyArrow, however Narwhals supports other dataframe libraries (See the home page for supported libraries).