Skip to main content

How to write a recipe that depends on CUDA

Recipes for packages that depend on the CUDA Toolkit typically are more complicated compared to other compiled-code recipes. This guide covers best practices and common situations for recipes that depend on CUDA.

Add the CUDA compiler​

Add the {{ compiler('cuda') }} template to your recipe to install NVCC and enable CUDA variants in your feedstock. Remember to rerender.

requirements:
build:
- ${{ compiler('cuda') }}

Pin the host environment​

Pin the cuda-version package to cuda_compiler_version in the host environment, so that any host dependencies are compatible with the CUDA compiler.

requirements:
host:
- cuda-version ${{ cuda_compiler_version }}.*

Only use the required CUDA components​

Do not use CUDA metapackages (e.g. cuda-toolkit) to specify dependencies. Instead, specify only the minimal subset of CUDA components that your package requires (e.g. libcufft-dev). Specifying a -dev/-devel package as a host requirement makes your package require the corresponding non-dev package at run time, because the -dev/-devel packages have run_exports.

Build both CUDA and non-CUDA variants​

If your recipe has separate variants for CUDA and non-CUDA builds:

  1. Use the cuda_compiler_version variable as a switch for the CUDA requirements.
  2. Give the CUDA variant a higher build number than the non-CUDA variant, so the solver prefers it where it can be installed.
  3. Add the __cuda virtual package as a runtime requirement of the CUDA variant. This makes the CUDA variant uninstallable on machines without a CUDA driver, which would otherwise download large GPU packages needlessly. Users without a CUDA driver get the non-CUDA variant instead.

For example:

context:
build_number: 0

build:
# Prefer the CUDA variant when it is installable
number: ${{ build_number + (100 if cuda_compiler_version != "None" else 0) }}

requirements:
build:
- if cuda_compiler_version != "None":
then: ${{ compiler('cuda') }}
host:
- if cuda_compiler_version != "None":
then:
- libcublas-dev
- cuda-version ${{ cuda_compiler_version }}.*
run:
# Makes the CUDA variant uninstallable without a CUDA driver
- if: cuda_compiler_version != "None"
then: __cuda

Support CUDA Enhanced Compatibility​

If your package's code already supports CUDA Enhanced Compatibility, make these changes to the recipe so that the conda package supports it too:

  1. Ignore the run exports from any CTK library -dev/-devel packages that your package depends on. Otherwise, the run exports would require runtime libraries with versions equal to or greater than the versions used to build the package.
  2. Ignore the run exports of the cuda-version package.
  3. Add explicit runtime dependencies (or constraints for soft/optional dependencies) that specify the desired version range for the dependencies whose run exports you ignored.

For example, because of run exports in the libcublas-dev package, a package that requires libcublas has a run requirement on libcublas corresponding to {{ cuda_compiler_version }} or newer. To make it compatible with all CUDA minor versions from the same CUDA major version family, add the following:

requirements:
build:
- ${{ compiler('cuda') }}
host:
- libcublas-dev
- cuda-version ${{ cuda_compiler_version }}.*
run:
# Since we've ignored the run export from libcublas-dev, we pin
# libcublas manually. Having a pin_compatible on cuda-version with
# max_pin='x' and min_pin='x' will constrain libcublas to the same
# major version as what we pinned in host.
- ${{ pin_compatible('cuda-version', max_pin='x', min_pin='x') }}
- libcublas
# Ignore run exports from CUDA libraries in the host section
ignore_run_exports:
from_package:
- libcublas-dev
# Ignore cuda-version itself; do not ignore exports from
# compiler('cuda'), which has other needed exports
by_name:
- cuda-version

Set CUDA architecture targets​

Packages built on conda-forge should target broad compatibility across CUDA devices. This means passing explicit compiler arguments to NVCC to target all supported CUDA architectures instead of accepting the compiler's default target.

Use variables set by the CUDA compiler conda package​

The CUDA compiler package activation script automatically sets the environment variables CUDAARCHS and NVCC_GENCODE to all supported CUDA architectures for the target host platform when CONDA_BUILD is detected and when they are not already set. Use these environment variables in your build script instead of hard-coding architectures. You then do not need to update your build scripts when new architectures become available in new releases of the CUDA Toolkit.

Use variables set by the PyTorch conda package​

The libtorch/pytorch packages similarly set CF_TORCH_CUDA_ARCH_LIST in their activation scripts. To keep the CUDA targets of a PyTorch module up to date, set TORCH_CUDA_ARCH_LIST=${CF_TORCH_CUDA_ARCH_LIST} in your build environment.

For example, in your build script:

export TORCH_CUDA_ARCH_LIST="$CF_TORCH_CUDA_ARCH_LIST"

Fix nvcuda.dll not found on Windows​

The scripts used to install the CUDA Toolkit on Windows cannot provide nvcuda.dll as part of the installation because no GPU is physically present in the CI machines. As a result, you might get linking errors in the postprocessing steps of conda build:

WARNING (arrow-cpp,Library/bin/arrow_cuda.dll): $RPATH/nvcuda.dll not found in packages,
sysroot(s) nor the missing_dso_whitelist.

.. is this binary repackaging?

For now, you will have to add nvcuda.dll to the missing_dso_whitelist:

build:
...
dynamic_linking:
missing_dso_allowlist:
- if: win
then: "*/nvcuda.dll"

Adopt a new CUDA version​

As new CUDA versions come out regularly, periodically conda-forge needs to decide how many versions will be supported within resource constraints. As of August 2026, conda-forge supports CUDA 12 and 13.

conda-forge manages the adoption of a new CUDA major version with a migration. The migration bot opens a pull request in your feedstock with the changes needed to build for the new version.

To update to the latest supported versions outside of a migration, or if your feedstock no longer builds old CUDA versions, rerender the feedstock. There may be other fixes needed for the feedstock depending on when it was last updated.