Get started with NixActions in minutes.
- Nix with flakes enabled
- For OCI executor: Docker daemon running
# flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixactions.url = "github:yourorg/nixactions";
};
outputs = { nixpkgs, nixactions, ... }:
let
system = "x86_64-linux"; # or "aarch64-darwin", etc.
pkgs = nixpkgs.legacyPackages.${system};
nixactionsLib = nixactions.lib.${system};
in {
packages.${system}.ci = import ./ci.nix {
inherit pkgs nixactions;
};
};
}# ci.nix
{ pkgs, nixactions }:
nixactions.mkWorkflow {
name = "ci";
jobs = {
test = {
executor = nixactions.executors.local;
steps = [
{ bash = "echo 'Hello, NixActions!'"; }
];
};
};
}# Build and run
$ nix run .#ci
# Or build first, then run
$ nix build .#ci
$ ./result/bin/cijobs = {
my-job = {
executor = nixactions.executors.local;
steps = [
{ bash = "echo 'Step 1'"; }
{ bash = "echo 'Step 2'"; }
];
};
};jobs = {
lint = { ... };
test = { ... };
build = {
needs = [ "lint" "test" ]; # Waits for both
...
};
};Jobs without dependencies run in parallel:
jobs = {
lint = { ... }; # Level 0 - runs immediately
test = { ... }; # Level 0 - runs in parallel with lint
build = {
needs = [ "lint" "test" ]; # Level 1 - waits for both
...
};
};{ pkgs, nixactions }:
nixactions.mkWorkflow {
name = "nodejs-ci";
jobs = {
test = {
executor = nixactions.executors.local;
steps = [
{
name = "install";
bash = "npm ci";
deps = [ pkgs.nodejs ];
}
{
name = "lint";
bash = "npm run lint";
deps = [ pkgs.nodejs ];
}
{
name = "test";
bash = "npm test";
deps = [ pkgs.nodejs ];
}
];
};
build = {
needs = [ "test" ];
executor = nixactions.executors.local;
outputs = {
dist = "dist/";
};
steps = [
{
name = "build";
bash = "npm run build";
deps = [ pkgs.nodejs ];
}
];
};
};
}{ pkgs, nixactions }:
nixactions.mkWorkflow {
name = "python-ci";
jobs = {
test = {
executor = nixactions.executors.local;
steps = [
{
name = "install";
bash = "pip install -r requirements.txt";
deps = [ pkgs.python311 ];
}
{
name = "lint";
bash = "flake8 src/";
deps = [ pkgs.python311Packages.flake8 ];
}
{
name = "test";
bash = "pytest";
deps = [ pkgs.python311Packages.pytest ];
}
];
};
};
}{ pkgs, nixactions }:
nixactions.mkWorkflow {
name = "deploy";
jobs = {
test = {
executor = nixactions.executors.local;
steps = [
{ bash = "npm test"; deps = [ pkgs.nodejs ]; }
];
};
deploy-staging = {
needs = [ "test" ];
condition = ''[ "$BRANCH" = "develop" ]'';
executor = nixactions.executors.local;
steps = [
{ bash = "deploy.sh staging"; }
];
};
deploy-production = {
needs = [ "test" ];
condition = ''[ "$BRANCH" = "main" ]'';
executor = nixactions.executors.local;
steps = [
{ bash = "deploy.sh production"; }
];
};
notify = {
needs = [ "test" ];
condition = "always()";
executor = nixactions.executors.local;
steps = [
{
bash = ''curl -X POST $SLACK_WEBHOOK -d '{"text":"CI complete"}' '';
deps = [ pkgs.curl ];
}
];
};
};
}Runs on the current machine:
executor = nixactions.executors.localRuns in Docker containers:
executor = nixactions.executors.oci {
extraPackages = [ nixactions.linuxPkgs.nodejs ];
}Note: Use nixactions.linuxPkgs for packages in OCI executor (required for cross-platform builds on macOS).
jobs = {
local-task = {
executor = nixactions.executors.local;
...
};
container-task = {
executor = nixactions.executors.oci { ... };
...
};
};jobs = {
build = {
outputs = {
dist = "dist/";
binary = "target/release/myapp";
};
steps = [
{ bash = "npm run build"; }
];
};
};jobs = {
deploy = {
needs = [ "build" ];
inputs = [ "dist" "binary" ];
steps = [
{ bash = "ls dist/"; }
];
};
};inputs = [
{ name = "frontend"; path = "public/"; }
{ name = "backend"; path = "server/"; }
]nixactions.mkWorkflow {
name = "ci";
env = {
CI = "true";
NODE_ENV = "test";
};
jobs = { ... };
}jobs = {
deploy = {
env = {
ENVIRONMENT = "production";
};
...
};
};{
name = "build";
env = {
NODE_OPTIONS = "--max-old-space-size=4096";
};
bash = "npm run build";
}$ API_KEY=secret123 nix run .#cijobs = {
deploy = {
steps = [
# Load secrets
(nixactions.actions.sopsLoad {
file = ./secrets.sops.yaml;
})
# Validate
(nixactions.actions.requireEnv [ "API_KEY" "DB_PASSWORD" ])
# Use secrets
{ bash = "deploy.sh"; }
];
};
};nixactions.mkWorkflow {
name = "ci";
envFrom = [
(nixactions.envProviders.file { path = ".env"; })
(nixactions.envProviders.sops { file = ./secrets.sops.yaml; })
(nixactions.envProviders.required [ "API_KEY" ])
];
jobs = { ... };
}{
name = "flaky-test";
bash = "npm test";
retry = {
max_attempts = 3;
backoff = "exponential";
min_time = 1;
max_time = 60;
};
}NixActions comes with 30+ examples:
# Basic examples
$ nix run .#example-simple
$ nix run .#example-parallel
$ nix run .#example-env-sharing
# Feature examples
$ nix run .#example-artifacts
$ nix run .#example-retry
$ nix run .#example-secrets
# Real-world examples
$ nix run .#example-complete
$ nix run .#example-python-ci
$ nix run .#example-nodejs-full-pipeline$ nix build .#ci
$ cat result/bin/ci$ NIXACTIONS_KEEP_WORKSPACE=1 nix run .#ci$ NIXACTIONS_LOG_FORMAT=structured nix run .#ci
$ NIXACTIONS_LOG_FORMAT=json nix run .#ci{ pkgs, nixactions }:
nixactions.mkWorkflow {
name = "production-ci";
env = {
CI = "true";
};
envFrom = [
(nixactions.envProviders.file { path = ".env"; required = false; })
];
jobs = {
# Level 0: Parallel checks
lint = {
executor = nixactions.executors.local;
steps = [
{
name = "eslint";
bash = "npm run lint";
deps = [ pkgs.nodejs ];
}
];
};
security = {
executor = nixactions.executors.local;
continueOnError = true;
steps = [
{
name = "audit";
bash = "npm audit";
deps = [ pkgs.nodejs ];
}
];
};
# Level 1: Tests
test = {
needs = [ "lint" ];
executor = nixactions.executors.local;
outputs = {
coverage = "coverage/";
};
steps = [
{
name = "test";
bash = "npm test -- --coverage";
deps = [ pkgs.nodejs ];
retry = {
max_attempts = 2;
backoff = "exponential";
};
}
];
};
# Level 2: Build
build = {
needs = [ "test" ];
executor = nixactions.executors.local;
outputs = {
dist = "dist/";
};
steps = [
{
name = "build";
bash = "npm run build";
deps = [ pkgs.nodejs ];
}
];
};
# Level 3: Deploy (only on main)
deploy = {
needs = [ "build" ];
condition = ''[ "$BRANCH" = "main" ]'';
executor = nixactions.executors.local;
inputs = [ "dist" ];
steps = [
(nixactions.actions.requireEnv [ "DEPLOY_KEY" ])
{
name = "deploy";
bash = "deploy.sh";
deps = [ pkgs.kubectl ];
}
];
};
# Level 3: Notify (always)
notify = {
needs = [ "build" ];
condition = "always()";
executor = nixactions.executors.local;
steps = [
{
name = "slack";
condition = "always()";
bash = ''
STATUS="success"
[ ${#FAILED_JOBS[@]} -gt 0 ] && STATUS="failure"
curl -X POST $SLACK_WEBHOOK -d "{\"status\":\"$STATUS\"}"
'';
deps = [ pkgs.curl ];
}
];
};
};
}- Architecture - Understand how NixActions works
- Actions - Deep dive into actions
- Executors - Learn about execution environments
- API Reference - Full API documentation