⏱ 8 min read  ·  ✅ Updated Jul 2026
🔥Amazon Prime Day 2026 is coming — don’t miss the best deals.See Top Deals →

Docker Hub Nvidia CUDA images look simple until you open the tag list and find several hundred entries that differ by strings like 12.4.1-cudnn-devel-ubuntu22.04. Pick wrong and you get a 6GB image that does nothing useful, or a 300MB one missing the compiler you needed. This guide decodes the tag structure, explains the three image variants and when each is correct, and covers the runtime configuration that causes most “container cannot see the GPU” reports.

Docker Hub Nvidia CUDA Images: Picking the Right Tag Fast
Docker Hub Nvidia CUDA Images: Picking the Right Tag Fast

Decoding the Nvidia CUDA Image Tag Structure

The official images live under the nvidia/cuda repository, and every tag follows the same pattern once you know where the boundaries are. The format is CUDA version, then optional cuDNN marker, then variant, then operating system. Read it in that order and the list stops being intimidating.

The Three Variants: base, runtime, devel

This is the decision that matters most, because it determines image size by an order of magnitude.

base contains the bare CUDA runtime libraries. It is the minimal option and is correct when your application ships its own CUDA dependencies. runtime adds the CUDA math libraries — cuBLAS, cuFFT, cuSPARSE — and is what most deployed applications need. devel adds the full toolkit including nvcc, headers, and static libraries, and is what you need to compile CUDA code.

Variant Contains Approx size Use when
base CUDA runtime only ~200–400 MB App bundles its own libs
runtime + cuBLAS, cuFFT, cuSPARSE ~1.5–2.5 GB Running trained models, inference
devel + nvcc, headers, static libs ~5–7 GB Compiling CUDA code or extensions

Reading a Full Tag String

Take nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04 and split it at the hyphens.

12.4.1 is the CUDA toolkit version, down to the patch. cudnn means the cuDNN deep learning library is included — omit it and you get a slimmer image without it. devel is the variant. ubuntu22.04 is the base OS; the alternatives are typically other Ubuntu LTS releases and RHEL-family images.

Pin the full patch version in anything you intend to reproduce. A tag like 12.4-devel-ubuntu22.04 without the patch number will resolve differently over time, and a build that worked in March will not necessarily work in September.

The Common Mistake: Shipping devel to Production

The single most frequent waste in CUDA containerisation is deploying a devel image because that is what the build needed. You are then shipping a compiler and a full header set to every production node, for nothing.

The fix is a multi-stage build: compile in devel, copy the artefacts into runtime. This routinely cuts a 7GB image to under 2GB, which matters when you are pulling it onto fifty nodes.

FROM nvidia/cuda:12.4.1-devel-ubuntu22.04 AS builder
WORKDIR /build
COPY . .
RUN make

FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04
COPY --from=builder /build/myapp /usr/local/bin/
CMD ["myapp"]

Making the GPU Visible Inside the Container

Almost every “the container cannot see my GPU” report resolves to the same root cause, and it is not the image. The driver never lives inside the container — it is passed through from the host by the NVIDIA Container Toolkit. No toolkit, no GPU, regardless of which tag you pulled.

The Runtime Requirement Everyone Skips

Install the NVIDIA Container Toolkit on the host, then verify with the canonical smoke test:

docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

If that prints your GPU table, the plumbing works and any subsequent failure is your application’s. If it errors about an unknown runtime or a missing device, the toolkit is not installed or the Docker daemon has not been restarted since it was.

Note what nvidia-smi reports inside a container: the host driver version and its maximum supported CUDA runtime. It does not report the image’s toolkit. A container showing “CUDA Version: 12.6” while running a 12.4 image is behaving correctly.

The Driver Floor That Silently Fails

The host driver must be new enough for the image’s CUDA version. This is the second most common failure, and it presents as a successful pull followed by a runtime error that points nowhere useful.

Image CUDA Min Linux host driver
11.8 520.61.05
12.1 530.30.02
12.4 550.54.14
12.8+ 570.26 (required for Blackwell / RTX 50)

Minor version compatibility helps in one direction only: an 11.x-era driver runs any 11.x image, and a newer driver runs older images. A driver older than the image’s floor is not rescued by anything.

Selecting Specific GPUs and Limiting Access

--gpus all is fine on a single-GPU workstation and wrong on a shared machine. Scope it explicitly:

docker run --rm --gpus '"device=0,1"' nvidia/cuda:12.4.1-runtime-ubuntu22.04 nvidia-smi
docker run --rm --gpus 1 nvidia/cuda:12.4.1-runtime-ubuntu22.04 nvidia-smi

In Compose, the equivalent lives under deploy.resources.reservations.devices with driver: nvidia and a capabilities: [gpu] entry. Omitting the capabilities line is a frequent cause of a container that starts cleanly and sees nothing.

The device indices Docker exposes follow PCI bus order, which is not always the order nvidia-smi prints on the host. On a machine with mixed GPUs this bites. Pin by UUID instead, which never reorders across reboots:

nvidia-smi --query-gpu=index,uuid,name --format=csv
docker run --rm --gpus '"device=GPU-4a1b2c3d-..."' nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

Also worth setting on shared hosts: a memory ceiling. Containers do not partition VRAM by default, so one job can allocate everything and starve the rest. Frameworks expose their own limits — PyTorch through torch.cuda.set_per_process_memory_fraction — and using them is cheaper than arbitrating disputes later.

Pros and Cons of the Official Nvidia CUDA Images

The official images are the correct default for most work, but they are not the only option and they are not free of trade-offs. Knowing where they are weak saves you from fighting them later.

What They Get Right

Coverage is the main argument. Nvidia maintains tags across a wide span of CUDA versions and base operating systems, so almost any pinned requirement has a matching image. Reproducing a 2023 environment is a matter of finding the tag, not rebuilding a toolchain.

They are also correctly layered. The base/runtime/devel split means you are not forced to ship a compiler to production, and the layers cache well across images that share a CUDA version.

Third, they are the reference implementation. When something breaks, the first useful diagnostic is whether it also breaks in the plain nvidia/cuda image — and having that baseline is worth more than it sounds.

Where They Fall Short

Size is the obvious complaint. A devel tag with cuDNN runs 5–7GB before you add anything. On constrained CI runners or metered bandwidth this is a real cost, and multi-stage builds mitigate it rather than solving it.

Second, they ship no framework. If you want PyTorch you are installing it yourself, and matching a pip wheel’s bundled CUDA runtime against the image’s toolkit is a common source of confusion. For framework work, the purpose-built images from the framework vendors are usually the better start.

Third, tag churn. Older tags get deprecated and occasionally disappear from Docker Hub. If a build depends on a specific tag, mirror it to your own registry rather than trusting it will still be there next year.

Choosing Between Official CUDA and Framework Images

The rule is simple. If you are compiling CUDA code or building custom kernels, start from nvidia/cuda:*-devel. If you are running PyTorch or TensorFlow, start from the framework’s own image — they have already solved the version matching, and reproducing that work by hand is a poor use of an afternoon.

The middle case is a custom extension against a framework. There, build in devel, then copy into the framework image rather than trying to install the framework into a CUDA image. Installing PyTorch into a CUDA image works, but you end up maintaining a version matrix the framework vendor already maintains for you, and their image is better tested than yours will be.

One habit that saves time regardless of which route you take: record the image digest rather than the tag in your deployment manifests. Tags are mutable, digests are not, and a rebuild that quietly pulls a different image is difficult to diagnose after the fact.

docker run --rm --gpus all -it \
  -v $(pwd):/workspace -w /workspace \
  nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04 bash

Cutting Image Size Without Breaking Things

Three techniques account for most of the savings, and none of them require exotic tooling. First, drop the cudnn marker if you are not running a deep learning framework — cuDNN alone accounts for a substantial fraction of the layer size, and plenty of CUDA workloads never touch it.

Second, clean up in the same layer you install. A separate RUN rm after an apt install removes nothing from the image, because the previous layer already recorded the files. Chain them:

RUN apt-get update && apt-get install -y --no-install-recommends \
      python3-pip git && \
    rm -rf /var/lib/apt/lists/*

Third, order your layers by volatility. Put the CUDA base and system packages first, your dependencies next, and your own source last. Docker caches by layer, and a code change should not invalidate a 2GB dependency install.

     See More:

Conclusion: Choosing a Docker Hub Nvidia CUDA Image

Working with Docker Hub Nvidia CUDA images comes down to three decisions made in order. Pick the variant by what you actually do — base if your app carries its own libraries, runtime for inference and deployment, devel only if you compile. Pin the full patch version, because an unpinned tag will drift and take your reproducibility with it. And match the CUDA version against your host driver floor before anything else, since a driver below the line fails at runtime with an error that will send you looking in the wrong place.

The two habits that prevent most problems: run the --gpus all ... nvidia-smi smoke test on the plain base image before debugging your own container, and use multi-stage builds so production never receives a compiler it will not use. Remember that nvidia-smi inside a container reports the host driver rather than the image toolkit — that discrepancy is expected, not a fault, and misreading it sends more people down blind alleys than any other single detail here.

Explore Our Guides & Free Tools