Using Kicad With Docker to Manage and Upgrade Release Versions

Reproducible and reliable KiCad environments using Docker

Introduction

KiCad is a wonderful tool that is constantly improving. Part of that is the steady release of new features, along with major version updates (approximately) once per year. Changing versions will give you some new features, fix some bugs, and introduce some new ones just like any other software update. If your system has only one version installed, upgrading becomes a significant decision. Once you update what do you do with older projects made with previous releases? It’s not just the main program either, there are the different parts libraries, the script control bindings, as well as any scripts or tooling that might need to be updated for the new version. All these components need to be managed in a reliable, repeatable way to ensure our designs remain accessible over time. Managing those changes, especially in a production or long-term support environment, isn’t trivial. Designs depend on stable libraries, predictable behavior, and consistent tool outputs. If you’re maintaining a complex board or a product family, one thing you don’t want is for your designs to churn.

Using Docker allows you to install all the libraries and tools in an isolated environment that will sit still.

My two primary motivations for building a Docker-based workflow around KiCad are:

  1. CI/CD for PCB design and release workflows - Reproducible builds, automated exports, and quality checks.
  2. Local installation of multiple KiCad versions - Keep different versions from interfering.

The Dockerfile

The following is also available in the kicad-make repo.

FROM kicad/kicad:9.0

ENV DEBIAN_FRONTEND=noninteractive

# Create a non-root user
ARG ORIGINALUSER=kicad
ARG USERNAME=user
ARG UID=1000
ARG GID=1000

USER root
RUN usermod -l $USERNAME -d /home/$USERNAME -m -s /bin/bash $ORIGINALUSER  \
    && groupmod -n $USERNAME $ORIGINALUSER \
    && apt-get update && apt-get install -y sudo \
    && echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Install Python, pip, and venv
RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    python3-venv \
    && rm -rf /var/lib/apt/lists/*

# Create a Python virtual environment
RUN python3 -m venv /opt/venv

# Activate the virtual environment and install Python packages
RUN /opt/venv/bin/pip install --upgrade pip \
    && /opt/venv/bin/pip install git+https://github.com/snhobbs/kicad-testpoints.git \
    && /opt/venv/bin/pip install git+https://github.com/snhobbs/InteractiveHtmlBom.git

# Install make
RUN apt-get update && apt-get install -y \
    make \
    xvfb \
    poppler-utils \
    && rm -rf /var/lib/apt/lists/*

# Set environment variables to use the virtual environment
ENV PATH="/opt/venv/bin:$PATH"
ENV PYTHONPATH="/usr/lib/python3/dist-packages"

# Set environment variables for the new user
ENV HOME=/home/${USERNAME}
WORKDIR /home/${USERNAME}
USER ${USERNAME}

CMD ["bash"]

Base Image: Starting with kicad/kicad:x.0

The official KiCad Docker image provides a complete setup for running the KiCad GUI and scripting tools.

Out of the box:

  • KiCad binaries (GUI and CLI)
  • Scripting support with Python bindings
  • System-level dependencies configured and ready

You can choose a specific version tag (e.g., 9.0, 8.0, 7.0) to lock in compatibility. If you want the latest bleeding-edge features, there’s also a nightly tag but use that with caution for production workflows.


Creating a Non-Root User in Docker

By default, Docker containers often run as root, which isn’t ideal especially when working with GUI applications or mapping volumes from the host. The KiCad images define the user ‘kicad’ but it’s easier to forget you’re using Docker if the host and docker user are the same.

To improve compatibility:

  • Rename the default kicad user to match the host user ($USERNAME)
  • Match UID and GID to prevent permission issues when sharing files with the host
  • Grant passwordless sudo access so tooling can elevate when needed

This step helps ensure your container behaves more like your local machine with better encapsulation.

The container drops to the non-root user context and sets the correct working directory. This allows tools to run inside the container just as you would on your desktop.


Running the Container

To run the container with access to your display (for GUI use), and mount your home directory:

#!/bin/sh
xhost +local:docker

docker run --rm \
  -e DISPLAY=$DISPLAY \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -v /usr/share/fonts:/usr/share/fonts \
  -v $HOME:$HOME \
  --device /dev/dri \
  --group-add video \
  kicad9 "$@"

Locally, I wrap this in a shell script and add it to my $PATH. But you can also call it verbatim, use an alias, or configure Docker Compose.

You can:

  • Launch the KiCad GUI for manual work
  • Use command-line tools like kicad-cli or kicad_testpoints, or Python scripts
  • Batch-export from Makefiles or CI pipelines

Keeping Your Tools Updated

To keep your tooling fresh:

  • Rebuild your Docker image regularly
  • Let pip upgrade Python packages inside the virtual environment
  • Update GitHub-based tools by pulling from their main branches

To stabilize builds:

  • Pin specific Git commit hashes or release tags
  • Version-lock tools in a requirements.txt or script

Installing Python and Managing Dependencies

I rely on tools that use the python bindings to automate certain tasks and generate useful things like testpoint reports, documentation, and to automatically check form factors.

  • We install Python 3, pip, and venv
  • A virtual environment is created at /opt/venv
  • PATH is updated to include the Python virtual environment
  • PYTHONPATH is set so KiCad’s bundled Python modules can be found

Setting up kicad-make & Dependencies

kicad-make is a build system for KiCad projects that uses Makefiles and Docker together to produce reliable outputs.

What it does:

  • Run ERC/DRC checks automatically
  • Create production ZIPs for manufacturing (Gerbers, drill files, IPC-2581, ODB++ in v9+)
  • Creates design releases with the design drawings and documentation

It’s especially useful when paired with Docker for reproducible CI builds. See the kicad-make GitHub repo for templates and usage examples.

I clone kicad-make locally and reference the file path when running it:

kicad9 make -f ~/software/kicad-make-v9/Makefile PROJECT=<project name> VERSION=<version> OUTDIR=$(pwd)/<version>-<date> -j$(nproc) manufacturing_release DIR=$(pwd)

Since volumes are mapped from the host, this just works. You can also clone it in the docker image. Since the PATH is setup in the docker image already everything maps automatically.

Currently installed tools include:

You can add your own tools here as needed. Using venv keeps the system environment clean and avoids conflicting with the system Python (well that’s a requirement now anyway).

Depenancies

  • make - No introduction necessary
  • xvfb - Virtual framebuffer for running GUI tools in headless environments. Needed for the InteractiveHtmlBom.
  • poppler-utils - Needed for pdfunite, used by kicad-make to merge documentation PDFs.

Building the Image

docker build -f kicad.9Dockerfile \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
--build-arg USERNAME=$(whoami) -t kicad9 .

Conclusion

This workflow has been a big help in keeping my projects consistent, from early prototyping to manufacturing handoff. If you’re maintaining KiCad-based projects across teams, versions, or products, it’s really worth taking the time to build a similar containerized environment.

Using Docker with KiCad helps you:

  • Keep designs reproducible
  • Isolate tool versions and dependencies
  • Automate exports and reduce churn in your design process
  • Enable CI pipelines for hardware design

How are you managing projects? Are there tools that your company finds particularly useful?