Skip to main content
Accelerate your workflows by pre-installing dependencies directly into your runner’s base image. Instead of installing packages at runtime during every job, custom base images let you create optimized runners with your tools already available, eliminating repetitive setup steps and reducing job execution time.

Choosing an approach

There are three ways to make custom software available to your jobs. They differ in how much of your existing setup you have to change, and in how much time each job spends getting the software in place:
  1. Custom base image - bake your software into the runner image itself, using APT packages or a custom Dockerfile. Namespace distributes and optimizes these images ahead of time, so a job does not pull an image at startup. This is the fastest of the three, and what we recommend if you can move your software into the runner image.
  2. Namespace registry - run your job in a container built from an image in your workspace’s private registry, nscr.io. Your runners are already authenticated to pull from it, so this is the shortest path if you want to reuse container images you already build.
  3. External registry - run your job in a container using GitHub’s own container: support, authenticating to your registry with GitHub Actions secrets. This requires the fewest changes, as your images stay where they are today.
Options 2 and 3 pull an image at the start of every job. You can offset much of that cost by enabling container image caching, which caches both the image layers and the unpacking step locally.

Inspect the standard base images

Before adding your own packages, check what Namespace already ships in its standard base images. You can browse the contents of each image in the dashboard, for example ubuntu-26.04, or from the CLI: List the available base images
Show everything installed in a specific image
The JSON output is handy for comparing the contents of two images, for example ubuntu-24.04 vs ubuntu-26.04:
See nsc github base-image describe for the full reference.

Custom base image

You can extend the Namespace base image in two ways. Selecting APT packages covers most cases and needs no Dockerfile, while a custom Dockerfile lets you install anything else, such as language toolchains or binaries fetched from a release page. Both are configured per Runner Profile, and both produce an image that Namespace distributes and optimizes ahead of your jobs.

Preinstalled packages

1

Enable custom base image

Go to the desired Runner Profile and select a customizable base image.
2

Select APT packages

Type the Ubuntu packages to install.You can find the list of available packages from the Ubuntu website.
3

Submit the profile

After updating your profile definition the custom base image will be built. Once the image is ready to use, you will see a confirmation in the profile editor.
You can modify the list of pre-installed packages at any time. Any update to the selection will automatically update the base image.

Custom Dockerfile base

Using a custom Dockerfile, you can add any dependencies on top of the Namespace base image. Dockerfile syntax is fully supported, allowing customization beyond pre-installing APT packages. Important to know:
  • The final layer must be based on NAMESPACE_BASE_IMAGE_REF. The base image contains the software required to integrate with GitHub, without it your workflows won’t start.
  • The user in the final image must be runner. GitHub’s runner software expects to run as this user.
  • After an image is built, it needs to be distributed and optimized. Workflows using this profile may take longer to start than normal while this is still in progress.
To get started with a Dockerfile-based custom image:
1

Enable custom base image

Go to the desired Runner Profile and select a customizable base image.
2

Add customization steps

Add your custom Dockerfile steps to the input. Make sure to build on NAMESPACE_BASE_IMAGE_REF in your final layer:
3

Submit the profile

After updating your profile definition the custom base image will be built. Once the image is ready to use, you will see a confirmation in the profile editor.
You can modify the Dockerfile at any time. Any update will automatically rebuild the base image. After a new image is built, it needs to be distributed and optimized before it can be used. This ensures your custom base images start with the same fast performance as Namespace’s standard base images.

Namespace registry

If you already build container images that contain your tooling, you can run your jobs in those images instead of baking the software into the runner’s base image. Every workspace comes with its own private container registry at nscr.io, and your runners are already authenticated to pull from it. Your workflow does not need registry credentials or secrets.
1

Push your image to nscr.io

Configure your local Docker (or your image build pipeline) to push to your workspace registry:
Your workspace identifier can be found in the Dashboard.
2

Reference the image in your job

Jobs running in a container need extra configuration to reach Namespace features such as Cache Volumes, Git mirrors, and in-runner builders. See Running Jobs in Containers for working examples.
The image is pulled at the start of every job. Enable container image caching in your runner profile to make repeated pulls complete in seconds.

External registry

If your images live in a registry outside Namespace, you can keep using them through GitHub’s own container job support. Store the registry credentials as GitHub Actions secrets and pass them to the container block:
This option requires no changes to where your images are built or stored. See GitHub’s documentation on defining credentials for a container registry for details. Pulling from an external registry is usually the slowest of the three options, as the image crosses the public internet whenever it is not cached. Container image caching reduces that cost, and as with nscr.io images, see Running Jobs in Containers to keep access to Namespace caching from inside the container.
Last modified on August 20, 2026