Skip to content

Pixi: Multi-Language Package and Workflow Manager

Pixi is a cross-platform package manager and workflow tool that manages both conda-forge packages and PyPI packages from a single project manifest. It replaces conda’s global environment model with project-local environments and automatic lockfiles.

Note

Pixi targets the same package ecosystem as conda but with a different workflow model. If you don’t need conda-forge packages, uv is a simpler choice. See When should I choose pixi over uv? for a detailed comparison.

When to use pixi

Use pixi when your project depends on native libraries that conda-forge packages more reliably than PyPI: CUDA toolkits, GDAL, HDF5, OpenCV, MKL, NetCDF. Some of these have PyPI packages, but conda-forge bundles the underlying C/C++/Fortran libraries so you don’t need to install them separately. Pixi also works well for mixed-language projects (Python + R, Python + C++) and for teams that want reproducible cross-platform lockfiles covering both conda and PyPI dependencies.

For pure Python projects, uv provides a simpler workflow.

Installation

curl -fsSL https://pixi.sh/install.sh | bash

This installs the pixi binary to ~/.pixi/bin (macOS/Linux) or %UserProfile%\.pixi\bin (Windows). See the official installation guide for other methods.

Project setup

Initialize a new project with pixi init:

pixi init my-project
cd my-project

This creates a pixi.toml manifest:

[workspace]
authors = ["Your Name <you@example.com>"]
channels = ["conda-forge"]
name = "my-project"
platforms = ["osx-arm64"]  # auto-detected from your system
version = "0.1.0"

[dependencies]

[tasks]

To use pyproject.toml instead (useful if you’re building a Python package):

pixi init --format pyproject my-project

With pyproject.toml, pixi configuration lives under [tool.pixi.*] sections (e.g. [tool.pixi.workspace], [tool.pixi.dependencies]), while standard [project] metadata remains portable to other Python tools.

Managing dependencies

Conda packages

pixi add python numpy pandas

PyPI packages

pixi add --pypi requests

Pixi resolves conda dependencies first, then resolves PyPI packages against what conda already installed. It uses uv internally for PyPI resolution.

Workspace dependencies

For workspaces with multiple packages, pixi workspace dependencies add adds shared dependencies at the workspace level:

pixi workspace dependencies add python numpy

Use package-level dependency tables when only one workspace member needs a package.

Installing the environment

pixi install

This creates a .pixi/ directory containing the project environment. The directory is local to the project and should be added to .gitignore (pixi does this automatically on pixi init).

Running commands

# Run a command in the project environment
pixi run python main.py

# Start an interactive shell
pixi shell

Running self-contained scripts

Pixi runs PEP 723 scripts directly, without a project directory or pixi.toml:

hello.py
# /// script
# requires-python = ">=3.11"
# dependencies = ["rich>=13.9.2"]
# ///
import rich

rich.print("Hi from [bold magenta]hello.py[/bold magenta]!")
pixi run --script hello.py

Pixi reads the metadata block, creates an isolated environment with the listed packages, and runs the script. pixi init --script writes an empty block into a script that has none (it refuses a script that already carries one), and pixi add --script fills the block in:

pixi init --script report.py
pixi add --script report.py --pypi rich

Mixing conda dependencies

Pixi extends the standard PEP 723 block with a [tool.pixi] section for conda packages, something uv and other PEP 723 runners cannot do. Omit --pypi and pixi add treats the package as a conda dependency:

pixi init --script earthquakes.py --channel conda-forge
pixi add --script earthquakes.py gdal
pixi add --script earthquakes.py --pypi httpx

Those commands leave the script’s own code alone and write the metadata above it:

earthquakes.py
# /// script
# requires-python = ">=3.11"
# dependencies = ["httpx"]
#
# [tool.pixi.workspace]
# channels = ["conda-forge"]
#
# [tool.pixi.dependencies]
# gdal = "*"
# ///

Another PEP 723 runner reads dependencies and ignores tool.pixi, so it installs httpx but not GDAL.

Running remote scripts and locking versions

pixi run --script accepts URLs, GitHub Gist URLs, or stdin (-):

pixi run --script https://example.com/fetch.py
pixi run --script - < fetch.py

Remote and stdin scripts must already carry a metadata block; only local paths can be edited, inspected, or locked.

To lock a script’s dependencies for reproducibility:

pixi lock --script hello.py

This writes a hello.py.pixi.lock sidecar next to the script.

Conda scripts

Pixi’s experimental conda-script format embeds conda dependencies and an entrypoint in a source file, including the channels used to resolve them. Unlike PEP 723, the format works with languages whose comment prefix contains no letters or digits (#, //, --, %), covering Python, R, Bash, C++, SQL, and MATLAB but not languages that use word-based comments like REM. Enable it once before running these scripts:

pixi config set experimental.conda-script true --global

For example, this R file declares its interpreter and stays valid R source code:

hello.R
# /// conda-script
# channels = ["conda-forge"]
# entrypoint = "Rscript ${SCRIPT}"
#
# [dependencies]
# r-base = "*"
# /// end-conda-script

cat("Hello from pixi!\n")

Run it without creating a workspace:

$ pixi run --script hello.R
⚠️ Running hello.R through `experimental.conda-script`, a draft format that may still change
✨ Pixi script (hello.R): Rscript ${SCRIPT}
Hello from pixi!

Pixi resolves the environment, caches it, and runs the declared entrypoint. With the experimental setting enabled, pixi init --script hello.R generates the metadata block and starter code from the file extension.

Tasks

Pixi includes a built-in task runner. Tasks are defined in pixi.toml and run within the project environment.

# Add tasks
pixi task add test "pytest -s"
pixi task add lint "ruff check ."

# Run a task
pixi run test

Tasks can also be defined directly in pixi.toml with dependencies on other tasks:

[tasks]
lint = "ruff check ."
test = { cmd = "pytest -s", depends-on = ["lint"] }

Multi-environment support

Pixi can define multiple environments from composable “features.” Each feature is a named set of dependencies; environments combine one or more features. Named environments include the default feature’s dependencies unless you set no-default-feature = true.

[dependencies]
python = ">=3.12"
numpy = ">=2.0"

[feature.test.dependencies]
pytest = ">=8"

[feature.docs.dependencies]
sphinx = ">=7"

[environments]
test = ["test"]
docs = ["docs"]

Run commands in a specific environment:

pixi run --environment test pytest
pixi run --environment docs sphinx-build docs build

Cross-platform lockfiles

Pixi resolves dependencies for all target platforms in a single pixi.lock file. Add platforms with:

pixi workspace platform add linux-64 win-64

The lockfile captures the full dependency graph for every platform and environment combination. Each platform is solved separately, so exact builds may differ across OSes, but every collaborator gets a reproducible install for their platform.

Pixi upgrades older lockfile formats automatically on the next pixi lock or pixi update, but older pixi builds may be unable to read a regenerated pixi.lock. Coordinate lockfile upgrades across collaborators and CI before committing one. Pixi lockfiles record build and host environments, avoid churn from comment-only manifest edits, and keep relative paths relative for Docker and cross-machine portability.

Tool management

Like pipx or uvx, pixi can install CLI tools globally or run them in temporary environments:

# Install a tool globally
pixi global install ruff

# Run a tool without installing it
pixi exec black --check .

# List globally installed tools
pixi global list

Building packages from source (preview)

Pixi Build lets pixi build packages from source instead of only consuming prebuilt conda packages. The system uses language-specific build backends inspired by Python’s PEP 517 build backend protocol: pixi-build-python for Python projects (using hatchling and uv internally) and pixi-build-rust for Rust projects.

Enable the feature with a preview flag in pixi.toml:

[workspace]
preview = ["pixi-build"]

Configure a build backend in the package manifest:

[package.build.backend]
name = "pixi-build-python"

[host-dependencies]
hatchling = "*"

[run-dependencies]
python = ">=3.12"

Build dependencies stay isolated from the runtime environment. Pixi rebuilds packages in dependency order with caching, so a monorepo with path dependencies (fibtable = { path = "." }) rebuilds only what changed.

SciPy, Xarray, Dask, and CPython have adopted pixi-build in early preview. See the pixi-build documentation for the full configuration reference.

Other useful commands

# Search for a package on configured channels
pixi search opencv

# Show the dependency tree
pixi tree

# Show environment and system info
pixi info

# Update dependencies to latest compatible versions
pixi update

Supply chain security

Pixi supports exclude-newer, which delays adoption of newly released packages by a configurable period. This gives malicious or broken packages time to be caught before they reach a project’s resolved dependencies.

Set a workspace-wide cooldown in pixi.toml:

[workspace]
exclude-newer = "7d"

Per-channel or per-package overrides are supported for packages under internal control:

[workspace]
channels = [
  "conda-forge",
  { channel = "https://prefix.dev/my-channel", exclude-newer = "0d" },
]
exclude-newer = "14d"

[exclude-newer]
my-internal-package = "0d"

The value accepts a duration ("7d", "30d") or an ISO date ("2026-01-01"). The setting applies to both conda and PyPI packages.

Last updated on