Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/conda/conda/llms.txt

Use this file to discover all available pages before exploring further.

Conda provides a Python API for programmatic access to its functionality. This allows you to integrate conda operations into your Python applications.
The Python API is currently in Beta. While in beta, expect both major and minor changes across minor releases. The API is defined in conda/api.py.

When to Use the Python API

Consider using the Python API when you need to:

Programmatic Control

Integrate conda operations into Python scripts, tools, or applications

Custom Tools

Build custom package managers or deployment tools

Automation

Automate environment management workflows

Integration

Integrate conda with CI/CD pipelines or other systems
For simple scripting, consider using conda CLI commands with subprocess instead. The Python API is best suited for deep integration needs.

Core Components

The conda Python API provides several high-level classes:

Solver

From conda/api.py:21:
class Solver:
    """
    A high-level API to conda's solving logic. Three public methods are provided
    to access a solution in various forms.

      * solve_final_state
      * solve_for_diff
      * solve_for_transaction
    """

    def __init__(
        self, prefix, channels, subdirs=(), specs_to_add=(), specs_to_remove=()
    ):
        """
        Args:
            prefix (str): The conda prefix / environment location
            channels (Sequence[Channel]): A prioritized list of channels
            subdirs (Sequence[str]): A prioritized list of subdirs
            specs_to_add (set[MatchSpec]): Package specs to add
            specs_to_remove (set[MatchSpec]): Package specs to remove
        """
Returns the final, solved state of the environment.
from conda.api import Solver
from conda.models.channel import Channel

solver = Solver(
    prefix="/path/to/env",
    channels=[Channel("conda-forge"), Channel("defaults")],
    specs_to_add=["numpy", "pandas"],
)

# Get the solved package list
final_state = solver.solve_final_state()

# final_state is a tuple of PackageRef in dependency order
for package in final_state:
    print(f"{package.name} {package.version}")

Solver Modifiers

From conda/api.py:14:
DepsModifier = _DepsModifier
"""Flags to enable alternate handling of dependencies."""

UpdateModifier = _UpdateModifier
"""Flags to enable alternate handling for updates of existing packages."""
Control how dependencies are handled:
  • NO_DEPS: Don’t install dependencies
  • ONLY_DEPS: Only install dependencies, not the package itself
  • UPDATE_DEPS: Update all dependencies to latest versions
  • UPDATE_DEPS_ONLY_DEPS: Update dependencies but not the main package
  • FREEZE_INSTALLED: Don’t update any installed packages
from conda.api import Solver, DepsModifier

solver = Solver(prefix="/path/to/env", ...)
result = solver.solve_final_state(
    deps_modifier=DepsModifier.UPDATE_DEPS
)
  • prune (bool): Remove packages no longer needed as dependencies
  • ignore_pinned (bool): Ignore pinned package configuration
  • force_remove (bool): Remove packages without checking dependents
  • force_reinstall (bool): Reinstall even if already satisfied

SubdirData

From conda/api.py:191:
class SubdirData:
    """
    High-level management and usage of repodata.json for subdirs.
    """

    def __init__(self, channel):
        """
        Args:
            channel (str or Channel): The target subdir
        """
from conda.api import SubdirData
from conda.models.channel import Channel

# Initialize for a specific channel and platform
subdir = SubdirData(Channel("conda-forge/linux-64"))

# Query for packages matching a spec
packages = subdir.query("numpy>=1.20")
for pkg in packages:
    print(f"{pkg.name} {pkg.version}")

PackageCacheData

From conda/api.py:284:
class PackageCacheData:
    """
    High-level management and usage of package caches.
    """

    def __init__(self, pkgs_dir):
        """
        Args:
            pkgs_dir (str): Path to the package cache directory
        """
from conda.api import PackageCacheData

cache = PackageCacheData("/path/to/pkgs")

# Query for packages in cache
cached_packages = cache.query("numpy")

for pkg in cached_packages:
    print(f"{pkg.name} {pkg.version} - {pkg.package_tarball_full_path}")

PrefixData

From conda/api.py:412:
class PrefixData:
    """
    High-level management and usage of conda environment prefixes.
    """

    def __init__(self, prefix_path):
        """
        Args:
            prefix_path (str): Path to the conda environment
        """
from conda.api import PrefixData

# Get information about an environment
prefix = PrefixData("/path/to/env")

# Iterate over installed packages
for record in prefix.iter_records():
    print(f"{record.name} {record.version}")

Complete Example

Here’s a complete example that creates an environment programmatically:
from conda.api import Solver
from conda.models.channel import Channel
from conda.base.context import context
import os

def create_environment(env_path, packages, channels=None):
    """
    Create a new conda environment programmatically.
    
    Args:
        env_path: Path where the environment will be created
        packages: List of package specs (e.g., ["python=3.11", "numpy"])
        channels: List of channel names (defaults to context.channels)
    """
    # Use default channels if none specified
    if channels is None:
        channels = context.channels
    
    # Convert channel names to Channel objects
    channel_objs = [Channel(c) for c in channels]
    
    # Create solver
    solver = Solver(
        prefix=env_path,
        channels=channel_objs,
        subdirs=context.subdirs,
        specs_to_add=packages,
    )
    
    # Solve and create transaction
    print(f"Solving environment for {len(packages)} packages...")
    transaction = solver.solve_for_transaction()
    
    # Display what will be installed
    print(f"\nWill install {len(transaction.link_precs)} packages:")
    for pkg in transaction.link_precs[:5]:  # Show first 5
        print(f"  - {pkg.name} {pkg.version}")
    if len(transaction.link_precs) > 5:
        print(f"  ... and {len(transaction.link_precs) - 5} more")
    
    # Execute the transaction
    print("\nExecuting transaction...")
    transaction.execute()
    
    print(f"\nEnvironment created at: {env_path}")

# Example usage
if __name__ == "__main__":
    env_path = os.path.expanduser("~/my-conda-env")
    packages = ["python=3.11", "numpy", "pandas", "matplotlib"]
    channels = ["conda-forge", "defaults"]
    
    create_environment(env_path, packages, channels)

Working with Context

The context object provides access to conda’s configuration.
from conda.base.context import context

# Access configuration
print(f"Channels: {context.channels}")
print(f"Subdirs: {context.subdirs}")
print(f"Package cache: {context.pkgs_dirs}")
print(f"Environment directories: {context.envs_dirs}")

# Check features
print(f"Offline mode: {context.offline}")
print(f"JSON output: {context.json}")
print(f"Verbosity: {context.verbosity}")

Error Handling

Import conda exceptions for proper error handling:
from conda.exceptions import (
    PackagesNotFoundError,
    UnsatisfiableError,
    EnvironmentLocationNotFound,
    CondaError,
)
from conda.api import Solver

try:
    solver = Solver(
        prefix="/path/to/env",
        channels=[Channel("conda-forge")],
        specs_to_add=["nonexistent-package"],
    )
    result = solver.solve_final_state()
    
except PackagesNotFoundError as e:
    print(f"Package not found: {e}")
except UnsatisfiableError as e:
    print(f"Cannot satisfy dependencies: {e}")
except EnvironmentLocationNotFound as e:
    print(f"Environment not found: {e}")
except CondaError as e:
    print(f"Conda error: {e}")

Best Practices

Use Context

Leverage the context object for configuration instead of hardcoding values.

Handle Errors

Always catch and handle conda exceptions appropriately.

Test Offline

Test your code with context.offline = True to ensure it handles offline scenarios.

Reload Data

Use .reload() methods sparingly - only when you know data is stale.
The Python API runs in the same process as your application. Be cautious of:
  • Global state modifications
  • Signal handlers
  • Thread safety (conda operations are not thread-safe)

API Reference

For detailed API documentation, see:

API Reference

Complete reference documentation for all Python API classes and methods

Next Steps

Plugin Development

Learn how to extend conda with plugins

CLI Reference

Command-line interface reference