Skip to main content
Learn how to create and manage multiple environments within a single Pixi workspace to handle different use cases like development, testing, and production.

Why Multiple Environments?

When developing a project, you often need different sets of tools and dependencies:
  • Development: All tools including linters, formatters, and debuggers
  • Testing: Testing frameworks and coverage tools
  • Production: Only runtime dependencies for deployment
  • Documentation: Tools for generating and building docs
With Pixi’s multiple environments, you can define all these in one workspace and switch between them easily.

Key Concepts

Features

A feature is a collection of:
  • Dependencies
  • Tasks
  • Channels
  • Platform configurations
Features aren’t useful on their own - they must be part of an environment. Define a feature:
[feature.test.dependencies]
pytest = "*"
pytest-cov = "*"

[feature.test.tasks]
test = "pytest tests/"

Environments

An environment is a collection of features that can be installed and activated. Define an environment:
[environments]
test = { features = ["test"], solve-group = "default" }

Default Feature

The default feature contains top-level dependencies:
[dependencies]
python = ">=3.11"
numpy = "*"
This is equivalent to:
[feature.default.dependencies]
python = ">=3.11"
numpy = "*"
The default feature is automatically included in all environments unless you use no-default-feature = true.

Getting Started

1
Create a Workspace
2
Start with a new Pixi workspace:
3
pixi init my-workspace
cd my-workspace
pixi add python
4
Project structure:
5
my-workspace/
├── .pixi/
│   └── envs/
│       └── default/
├── pixi.lock
└── pixi.toml
6
Add a Feature
7
Add a test feature with pytest:
8
pixi add --feature test pytest
9
This adds to pixi.toml:
10
[feature.test.dependencies]
pytest = "*"
11
Create an Environment
12
Create a test environment using the test feature:
13
pixi workspace environment add test --feature test
14
Result in pixi.toml:
15
[environments]
test = { features = ["test"] }
16
Use the Environment
17
Run commands in the test environment:
18
pixi run --environment test pytest --version
19
Expected Output:
20
✨ Pixi task (test environment): pytest --version
pytest 8.3.4
21
Check the environment structure:
22
.pixi/
└── envs/
    ├── default/
    └── test/

Testing Multiple Python Versions

A common use case is testing your code against multiple Python versions.
1
Make Python Flexible
2
Allow any Python version in the default feature:
3
pixi add "python=*"
4
Create Version Features
5
Add features for each Python version:
6
pixi add --feature py311 python=3.11
pixi add --feature py312 python=3.12
pixi add --feature py313 python=3.13
7
Create Test Environments
8
Combine Python version features with the test feature:
9
pixi workspace environment add test-py311 --feature py311 --feature test
pixi workspace environment add test-py312 --feature py312 --feature test
pixi workspace environment add test-py313 --feature py313 --feature test
10
Result:
11
[feature.py311.dependencies]
python = "3.11.*"

[feature.py312.dependencies]
python = "3.12.*"

[feature.py313.dependencies]
python = "3.13.*"

[feature.test.dependencies]
pytest = "*"

[environments]
test-py311 = { features = ["py311", "test"] }
test-py312 = { features = ["py312", "test"] }
test-py313 = { features = ["py313", "test"] }
12
Run Tests
13
Test against all Python versions:
14
pixi run --environment test-py311 pytest
pixi run --environment test-py312 pytest
pixi run --environment test-py313 pytest

Development, Testing, and Production

Create separate environments for different stages:
1
Create a Clean Workspace
2
pixi init production-project
cd production-project
3
Add Features
4
Define dependencies for each stage:
5
# Runtime dependencies (default feature)
pixi add numpy python

# Development tools
pixi add --feature dev jupyterlab ruff mypy

# Testing tools
pixi add --feature test pytest pytest-cov
6
Result:
7
[dependencies]
python = ">=3.11"
numpy = "*"

[feature.dev.dependencies]
jupyterlab = "*"
ruff = "*"
mypy = "*"

[feature.test.dependencies]
pytest = "*"
pytest-cov = "*"
8
Create Environments
9
Define environments with solve groups for consistency:
10
# Production: only runtime dependencies
pixi workspace environment add production --solve-group prod

# Test: runtime + testing
pixi workspace environment add test --feature test --solve-group prod

# Development: runtime + dev + test (default environment)
pixi workspace environment add default --feature dev --feature test --solve-group prod --force
11
Result:
12
[environments]
production = { solve-group = "prod" }
test = { features = ["test"], solve-group = "prod" }
default = { features = ["dev", "test"], solve-group = "prod" }
13
Add Tasks
14
Define tasks for each environment:
15
[tasks]
start = "python -m my_app"

[feature.dev.tasks]
dev = "jupyter lab"
lint = "ruff check ."

[feature.test.tasks]
test = "pytest tests/"
coverage = "pytest --cov=my_app tests/"
16
Verify Consistency
17
Check that all environments use the same versions:
18
pixi list --explicit
19
Output:
20
Environment: default
Package     Version  Build               Size      Kind   Source
jupyterlab  4.3.4    pyhd8ed1ab_0        6.9 MiB   conda  jupyterlab
numpy       2.2.1    py313ha4a2180_0     6.2 MiB   conda  numpy
pytest      8.3.4    pyhd8ed1ab_1        253 KiB   conda  pytest
python      3.13.1   h4f43103_105_cp313  12.3 MiB  conda  python
ruff        0.8.4    py313h8f79df9_0     8.1 MiB   conda  ruff

Environment: test
Package  Version  Build               Size      Kind   Source
numpy    2.2.1    py313ha4a2180_0     6.2 MiB   conda  numpy
pytest   8.3.4    pyhd8ed1ab_1        253 KiB   conda  pytest
python   3.13.1   h4f43103_105_cp313  12.3 MiB  conda  python

Environment: production
Package  Version  Build               Size      Kind   Source
numpy    2.2.1    py313ha4a2180_0     6.2 MiB   conda  numpy
python   3.13.1   h4f43103_105_cp313  12.3 MiB  conda  python
21
Notice all environments use the same Python and numpy versions!

Solve Groups

Solve groups ensure dependency versions are consistent across environments.

Without Solve Groups

[environments]
default = { features = ["dev"] }
test = { features = ["test"] }
Environments are solved independently and may have different versions.

With Solve Groups

[environments]
default = { features = ["dev"], solve-group = "default" }
test = { features = ["test"], solve-group = "default" }
Environments share the same dependency versions, preventing version mismatches between development and testing.
Use solve groups to ensure your tests run against the same dependency versions as your development environment.

Environment Without Default Feature

Sometimes you want an environment without the default dependencies:
pixi add --feature docs mkdocs mkdocs-material
pixi workspace environment add docs --feature docs --no-default-feature
Result:
[feature.docs.dependencies]
mkdocs = "*"
mkdocs-material = "*"

[environments]
docs = { features = ["docs"], no-default-feature = true }
Verify it doesn’t include default dependencies:
pixi list --explicit --environment docs
Output:
Environment: docs
Package         Version  Build         Size     Kind   Source
mkdocs          1.6.1    pyhd8ed1ab_1  3.4 MiB  conda  mkdocs
mkdocs-material 9.5.47   pyhd8ed1ab_0  5.8 MiB  conda  mkdocs-material

Feature-Specific Tasks

Tasks can be associated with features:
[tasks]
start = "python -m app"

[feature.test.tasks]
test = "pytest tests/"
coverage = "pytest --cov=app tests/"

[feature.docs.tasks]
docs = "mkdocs serve"
build-docs = "mkdocs build"

[feature.dev.tasks]
lint = "ruff check ."
format = "ruff format ."
Run feature-specific tasks:
pixi run test      # Automatically uses test environment
pixi run docs      # Automatically uses docs environment
pixi run lint      # Uses default environment (has dev feature)
If a task exists in multiple environments, Pixi will prompt you to choose which one.

Platform-Specific Environments

Define platform-specific dependencies:
[feature.unix.dependencies]
ncurses = "*"

[feature.unix.target.linux-64.dependencies]
systemd = "*"

[feature.unix.target.osx-arm64.dependencies]
darwin = "*"

[environments]
unix = { features = ["unix"], platforms = ["linux-64", "osx-arm64"] }

CI/CD Integration

GitHub Actions

Test multiple environments in parallel:
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [test-py311, test-py312, test-py313]
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: prefix-dev/setup-pixi@v0
        with:
          environments: ${{ matrix.environment }}
      
      - name: Run tests
        run: pixi run -e ${{ matrix.environment }} test

Docker Builds

Use the production environment in Docker:
FROM ghcr.io/prefix-dev/pixi:latest

WORKDIR /app
COPY . .

RUN pixi install --environment production

CMD ["pixi", "run", "--environment", "production", "start"]

Complete Example

Here’s a complete pixi.toml with multiple environments:
[workspace]
name = "my-app"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"]

# Runtime dependencies
[dependencies]
python = ">=3.11"
numpy = ">=2.0"
pandas = ">=2.0"

# Development tools
[feature.dev.dependencies]
jupyterlab = "*"
ruff = "*"
mypy = "*"
ipython = "*"

[feature.dev.tasks]
dev = "jupyter lab"
lint = "ruff check ."
format = "ruff format ."
type-check = "mypy src/"

# Testing tools
[feature.test.dependencies]
pytest = "*"
pytest-cov = "*"
pytest-asyncio = "*"

[feature.test.tasks]
test = "pytest tests/"
coverage = "pytest --cov=my_app --cov-report=html tests/"
test-verbose = "pytest -v tests/"

# Documentation
[feature.docs.dependencies]
mkdocs = "*"
mkdocs-material = "*"
mkdocstrings = { version = "*", extras = ["python"] }

[feature.docs.tasks]
docs = "mkdocs serve"
build-docs = "mkdocs build"

# Python versions
[feature.py311.dependencies]
python = "3.11.*"

[feature.py312.dependencies]
python = "3.12.*"

[feature.py313.dependencies]
python = "3.13.*"

# Application tasks
[tasks]
start = "python -m my_app"
clean = "find . -type d -name __pycache__ -delete"

# Environments
[environments]
# Development environment (default)
default = { features = ["dev", "test"], solve-group = "default" }

# Testing environments for different Python versions
test-py311 = { features = ["py311", "test"], solve-group = "test" }
test-py312 = { features = ["py312", "test"], solve-group = "test" }
test-py313 = { features = ["py313", "test"], solve-group = "test" }

# Production environment
production = { solve-group = "default", no-default-feature = false }

# Documentation environment
docs = { features = ["docs"], no-default-feature = true }

Best Practices

Use solve groups for related environments: Environments that should share versions (like dev and test) should be in the same solve group.
Keep production minimal: The production environment should only include runtime dependencies.
Organize features by purpose: Group related dependencies and tasks into features (dev, test, docs).
Use no-default-feature sparingly: Only use it for truly independent environments like documentation.

Troubleshooting

Tasks Not Found

If a task isn’t found, check which environments include its feature:
pixi info

Version Conflicts

If environments have conflicting versions, ensure they’re in the same solve group:
[environments]
env1 = { features = ["feat1"], solve-group = "default" }
env2 = { features = ["feat2"], solve-group = "default" }

Environment Not Created

Manually install an environment:
pixi install --environment test

Next Steps