A Docker/Podman image that exactly mirrors the CI compile check, with all build dependencies pre-installed. It is an optional complement to building natively — every contributor can continue using their own environment as before.
- Immutable/atomic Linux (Fedora Silverblue, NixOS, SteamOS, etc.): avoids installing and layering 50+ build packages that break on weekly OS rebuilds.
- Infrequent contributors: get a working build environment without a permanent setup.
- Reproducing CI failures: your local environment matches the CI container exactly, so a build that passes here passes CI.
- Sandboxing AI coding agents: tools running inside the container can only access the mounted workspace — host SSH keys, credentials, private documents, and other projects remain invisible to them.
Docker (or Podman) is required for all usage options below. Install one:
| Platform | Command / link |
|---|---|
| Debian / Ubuntu | sudo apt install docker.io or Docker CE (recommended — includes BuildKit) |
| Fedora / RHEL | sudo dnf install docker or Docker CE |
| Arch | sudo pacman -S docker |
| openSUSE | sudo zypper install docker |
| macOS | brew install --cask docker or brew install podman |
| Windows | Docker Desktop |
On Linux, add your user to the docker group and log out/in before using it:
sudo usermod -aG docker "$USER"Podman is a rootless drop-in replacement on Linux (alias docker=podman).
See the Podman installation guide.
No IDE, no extra tooling — just build and run the container directly.
# Build the image once (from the repository root)
docker build -t darktable-dev -f .devcontainer/Dockerfile .
# Verify the build compiles (same environment as CI)
docker run --rm --user "$(id -u):$(id -g)" \
-v "$PWD":/workspace -w /workspace \
darktable-dev \
bash -lc './build.sh --prefix /tmp/dt --build-type Release'
# Build an AppImage for GUI testing on the host
docker run --rm --user "$(id -u):$(id -g)" \
-v "$PWD":/workspace -w /workspace \
-e APPIMAGE_EXTRACT_AND_RUN=1 \
darktable-dev \
bash -lc './tools/appimage-build-script.sh'The AppImage appears in build/Darktable-*.AppImage and can be run on the host.
Replace
dockerwithpodmanif you use Podman.
A Dev Container adds IDE integration on top of the same Docker image: editor extensions, CMake integration, debugger support, etc.
Install the Dev Containers extension, then open this repository and click "Reopen in Container" when prompted (or F1 → Dev Containers: Reopen in Container). Git submodules are initialized automatically.
Install the Dev Containers plugin and follow the JetBrains Dev Containers guide.
Install the devcontainer CLI:
npm install -g @devcontainers/cliThen:
# Start the container
devcontainer up --workspace-folder .
# Open a shell
devcontainer exec --workspace-folder . bashVS Code and JetBrains bundle their own devcontainer implementation — you only need to install the CLI separately when using other editors or working purely in a terminal.
The VS Code extensions listed in devcontainer.json are
all from Microsoft (ms-vscode.*) or well-established publishers.
Inside the container (any option):
# Standard development build
./build.sh --prefix /tmp/dt --build-type RelWithDebInfo
# Debug build
./build.sh --prefix /tmp/dt --build-type Debug
# Switch to Clang 22 (matches CI LLVM22 path)
export CC=clang-22 CXX=clang++-22
./build.sh --prefix /tmp/dt --build-type RelWithDebInfoThe container has no display. GUI testing uses an AppImage built inside the container and run on the host.
# APPIMAGE_EXTRACT_AND_RUN=1 is required — FUSE is not available in containers
APPIMAGE_EXTRACT_AND_RUN=1 ./tools/appimage-build-script.shThe AppImage is created in build/Darktable-*.AppImage. Run it on the host:
chmod +x build/Darktable-*.AppImage
./build/Darktable-*.AppImage --configdir ~/.config/darktable-testUsing --configdir avoids touching your production darktable configuration.
libcmocka-dev is already installed:
./build.sh --prefix /tmp/dt --build-type RelWithDebInfo -- -DBUILD_TESTING=ON
cd build && ctestThe Dockerfile is the single source of truth for the build environment. Inspect it for the exact base image, compiler versions, and package list.
.github/workflows/build-docker.yml automatically builds the image and
publishes it to the GitHub Container Registry (GHCR) whenever the Dockerfile
changes on the master branch. The pre-built image is available at:
ghcr.io/darktable-org/darktable-build:latest
Using the pre-built image skips the local build step:
docker pull ghcr.io/darktable-org/darktable-build:latest
docker run --rm --user "$(id -u):$(id -g)" \
-v "$PWD":/workspace -w /workspace \
ghcr.io/darktable-org/darktable-build:latest \
bash -lc './build.sh --prefix /tmp/dt --build-type Release'This happens with older Docker installations (e.g. Ubuntu's docker.io package)
that don't use BuildKit by default. Fix by installing Docker CE via the
official Docker Engine docs
(which includes docker-buildx-plugin), or just add the plugin to an existing
installation:
sudo apt install docker-buildx-pluginAlways set APPIMAGE_EXTRACT_AND_RUN=1 — FUSE is not available inside containers.
git submodule update --init --recursivePass --user "$(id -u):$(id -g)" to docker run (as shown in the examples
above), or mark the path as safe inside the container:
git config --global --add safe.directory /workspacesudo apt-get update && sudo apt-get install <package>VS Code: F1 → Dev Containers: Rebuild Container
CLI: devcontainer up --workspace-folder . --remove-existing-container
.devcontainer/
├── Dockerfile # Build environment (mirrors CI)
├── devcontainer.json # IDE/tooling configuration
└── README.md # This file
.github/workflows/
└── build-docker.yml # Publishes the image to GHCR on Dockerfile changes