Skip to Content
GuidesDeterminate on GitLab

Determinate on GitLab

GitLab CI/CD is compatible with Determinate Nix, FlakeHub, and FlakeHub Cache. From a GitLab pipeline you can:

  1. Publish flakes to FlakeHub
  2. Push store paths to FlakeHub Cache

Both rely on the OpenID Connect (OIDC) tokens that GitLab issues to your jobs, so you never need to store a static credential in your project’s CI variables.

Onboarding

To allow authentication from GitLab to FlakeHub, you must:

  1. Find your GitLab group’s numeric ID. To copy it from the UI, open your group, select Actions (the vertical ellipsis) in the upper-right corner of the group overview page, then select Copy Group ID.

    You can also fetch it from the GitLab API:

    Query the GitLab API for your group ID
    # Add curl and jq to your current shell session nix shell "https://flakehub.com/f/NixOS/nixpkgs/0.1#curl" "https://flakehub.com/f/NixOS/nixpkgs/0.1#jq" gitlab_group="my-group" # Your GitLab group's path curl "https://gitlab.com/api/v4/groups/${gitlab_group}" | jq -r '.id'
  2. Contact our support with your GitLab group ID and your FlakeHub organization name. If you run a self-managed GitLab instance rather than gitlab.com, include your instance’s URL as well, because that determines the token issuer that FlakeHub needs to trust.

How authentication works

Every job that talks to FlakeHub requests its own OIDC token using GitLab’s id_tokens keyword. Set the audience (aud) to api.flakehub.com:

.gitlab-ci.yml
build: id_tokens: FLAKEHUB_GITLAB_CI_TOKEN: aud: "api.flakehub.com"

You can name the variable whatever you like. Pass that name, without a $ prefix, to determinate-nixd login gitlab-pipeline:

Log in to FlakeHub on GitLab CI/CD
determinate-nixd login gitlab-pipeline \ --jwt-env-var FLAKEHUB_GITLAB_CI_TOKEN

Our flakehub-push component handles all of this for you, so you only need to write this out by hand when you’re pushing to FlakeHub Cache.

Publishing flakes to FlakeHub

To publish a flake from GitLab, include our flakehub-push component. It requests its own OIDC token, installs Determinate Nix, and pushes the flake, so this is the entire configuration:

.gitlab-ci.yml
stages: - "release" include: - component: "gitlab.com/DeterminateSystems/flakehub-push/component@main" inputs: stage: "release" visibility: "unlisted" # Could also be `public` or `private`

By default the component publishes a rolling release every time your default branch is updated. To publish tagged releases from your Git tags instead, set tagged to true and rolling to false:

.gitlab-ci.yml
stages: - "release" include: - component: "gitlab.com/DeterminateSystems/flakehub-push/component@main" inputs: stage: "release" tagged: true rolling: false

These are the inputs you’re most likely to reach for:

InputDescriptionDefault
stageThe pipeline stage in which the job runs.release
visibilitypublic, unlisted, or private.public
rollingPublish rolling releases from your default branch.true
rolling-minorThe SemVer minor version for rolling releases.1
taggedPublish using the current Git tag.false
namePublish under a name other than {group}/{project}. The group must match your GitLab root group.${CI_PROJECT_PATH}
directoryThe path of your flake relative to the repository root, for subflakes.The repository root
labelsComma-separated labels to attach to the flake.None
spdx-expressionAn SPDX license expression for your flake.None
include-output-pathsRegister each flake output’s store paths with FlakeHub.false

Pushing store paths to FlakeHub Cache

To push to FlakeHub Cache, install Determinate Nix, log in with the job’s OIDC token, and run Magic Nix Cache, which watches Determinate Nixd’s post-build events and uploads each store path as it’s built.

.gitlab-ci.yml
stages: - "build" build: stage: "build" image: "ubuntu:24.04" # Request an OIDC token from GitLab for FlakeHub id_tokens: FLAKEHUB_GITLAB_CI_TOKEN: aud: "api.flakehub.com" variables: MAGIC_NIX_CACHE_CLOSURE_URL: "https://install.determinate.systems/magic-nix-cache-closure/branch/main/X64-Linux?ci=gitlab" MAGIC_NIX_CACHE_LISTEN: "127.0.0.1:37515" MAGIC_NIX_CACHE_STARTUP_FILE: "/tmp/mnc-startup" before_script: - apt-get update && apt-get install --yes curl xz-utils script: # Install Determinate Nix and start Determinate Nixd. Containers don't run # systemd, so install with `--init none` and start Determinate Nixd yourself - | curl --proto '=https' --tlsv1.2 -sSf -L "https://install.determinate.systems/nix?ci=gitlab" \ | sh -s -- install linux --no-confirm --init none nohup /usr/local/bin/determinate-nixd daemon &>/tmp/dnixd.log & export NIX_REMOTE="daemon" export PATH="${PATH}:/nix/var/nix/profiles/default/bin" for n in {1..100}; do if determinate-nixd status &>/dev/null; then echo "Determinate Nixd started up after ${n} attempt(s)" break fi sleep 0.1 done # Fail the job if Determinate Nixd never became ready determinate-nixd status # Log in to FlakeHub using the token that GitLab issued for this job - determinate-nixd login gitlab-pipeline --jwt-env-var FLAKEHUB_GITLAB_CI_TOKEN # Acquire the `magic-nix-cache` executable, start it, and wait for it to come up - | mnc_closure="$(curl -L "${MAGIC_NIX_CACHE_CLOSURE_URL}" \ | xz -d \ | nix-store --import \ | tail -n1)" ln -sf "${mnc_closure}/bin/magic-nix-cache" /usr/bin/magic-nix-cache nohup magic-nix-cache \ --listen "${MAGIC_NIX_CACHE_LISTEN}" \ --use-flakehub \ --startup-notification-file "${MAGIC_NIX_CACHE_STARTUP_FILE}" \ &>/tmp/mnc.log & for n in {1..30}; do if [ -e "${MAGIC_NIX_CACHE_STARTUP_FILE}" ]; then echo "Magic Nix Cache started up after ${n} attempt(s)" break fi echo "Waiting on Magic Nix Cache; attempt ${n}" sleep 2 done if [ ! -e "${MAGIC_NIX_CACHE_STARTUP_FILE}" ]; then echo "Magic Nix Cache didn't start up within 60 seconds; exiting" exit 1 fi # Build whatever you like. Everything built from here on is pushed to FlakeHub Cache - nix build ".#packages.x86_64-linux.default" # Drain any remaining store paths to FlakeHub Cache - curl --fail -XPOST "http://${MAGIC_NIX_CACHE_LISTEN}/api/workflow-finish"

GitLab issues a job’s OIDC token once, when the job starts, and provides no way to request a fresh one mid-job. Magic Nix Cache therefore can’t refresh its FlakeHub credentials on GitLab, unlike on GitHub Actions or Buildkite. Keep jobs that push to FlakeHub Cache short enough to finish before the token expires.

The example above targets a Docker-based runner, which is what gitlab.com’s shared runners use (they run the docker+machine executor). On a shell executor running on a systemd host, you can install with --init systemd, source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh, and skip starting Determinate Nixd by hand.

Last updated on