Skip to content

Instantly share code, notes, and snippets.

@srid
Last active October 30, 2025 14:34
Show Gist options
  • Select an option

  • Save srid/258ea7c00998737268ae1573609bb8e3 to your computer and use it in GitHub Desktop.

Select an option

Save srid/258ea7c00998737268ae1573609bb8e3 to your computer and use it in GitHub Desktop.

Build Strategy

Note

Claude Code generated summary of how https://github.com/ekala-project/eka-ci does building of drvs.

Overview

This document explains how EkaCI discovers, lists, and builds Nix derivations.

1. Listing Derivations

Command

nix-eval-jobs <file.nix>

Can also work with flakes:

nix-eval-jobs --flake <flake-ref>#<attr>

Output Format

JSON stream, one derivation per line:

{
  "attr": "grpc",
  "attrPath": ["grpc"],
  "drvPath": "/nix/store/qkgrb8v2...-grpc-1.70.0.drv",
  "name": "grpc-1.70.0",
  "outputs": {"out": "/nix/store/rn3nlskr54...-grpc-1.70.0"},
  "system": "x86_64-linux"
}

See: backend/server/src/nix/nix_eval_jobs.rs:52-54

Example Job File

let
  pkgs = import <nixpkgs> {};
in
{
  inherit (pkgs) stdenv;
}

See: examples/simple_job/stdenv.nix

2. Discovering Dependencies

For each drv from nix-eval-jobs:

Get All Transitive Dependencies

nix-store --query --requisites <drv-path>

Returns all .drv files needed (filters out non-drv inputSrcs).

See: backend/server/src/nix/mod.rs:130-131

Get Dependency Graph

nix-store --query --graph <drv-path>

Returns graphviz format showing edges between drvs. Parsed to extract (reference, referrer) pairs where referrer depends on reference.

See: backend/server/src/nix/mod.rs:197-198

Get Derivation Metadata

nix derivation show <drv-path>

Returns JSON with system and requiredSystemFeatures.

See: backend/server/src/nix/derivation_show.rs:38-39

3. Build Scheduling

Which Drvs Get Built?

All derivations from nix-eval-jobs output + their full dependency graphs.

Build Order: Smart Dependency-Aware Scheduling

A drv is buildable only when ALL direct dependencies have successfully built:

deps.into_iter()
    .all(|x| x.build_state == DrvBuildState::Completed(DrvBuildResult::Success))

See: backend/server/src/db/model/build_event.rs:278-280

The Scheduling Flow

  1. Initial check (backend/server/src/scheduler/ingress.rs:76)

    • Each drv from eval → IngressService
    • Checks is_drv_buildable()
    • If buildable → send to BuildQueue
    • If not → stays in database, waiting
  2. Build execution (backend/server/src/scheduler/build/builder_thread.rs:105-107)

    nix-build <drv-path> --builders <builder-config>
    • Runs with configured max_jobs in parallel per platform
    • Default: 4 parallel builds per local builder
  3. After successful build (backend/server/src/scheduler/recorder.rs:107-111)

    • Get all downstream drvs (things that depend on this)
    • Re-check each one: "are you buildable now?"
    • If yes → queue for building
  4. After failed build

    • Mark as failed in database
    • Downstream drvs remain unbuildable (dependency failure)

Platform Routing

Builds route to platform-specific queues based on drv's system attribute:

  • system = "builtin" → routes to default platform
  • Otherwise → routes to matching platform queue

See: backend/server/src/scheduler/build/queue.rs:72-76

Round-robin across available builders for that platform.

See: backend/server/src/scheduler/build/system_queue.rs:47-51

Build Order Summary

Bottom-up, dependency-first, maximally parallel

  • Leaf dependencies (no deps) build first
  • As each completes, unlocks downstream drvs
  • All buildable drvs run concurrently (up to max_jobs limit)
  • No drv builds until ALL its dependencies succeed
  • If any dependency fails → downstream drvs never build

This is like Hydra's approach - ensures you don't waste time building things that will fail anyway!

4. Platform Detection

Current System

nix-instantiate --eval --raw -E "builtins.currentSystem"

See: backend/server/src/scheduler/build/queue.rs:92-94

Available Systems

nix config show

Parse output for system = ... line.

See: backend/server/src/scheduler/build/builder.rs:105-106

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment