$ nixx

// reference

API reference

Every public function and the options it accepts — sourced from lib.nix / writers.nix. For the narrative guide, see API.md on GitHub.

Constructors

nixx.<ctor> ''body'' makes a block tagged with a language. Call it as a function to attach options: bun ''body'' { compile = true; }.

constructor __lang mkApps? in a runner
sh · bash bash inline
uv python-uv heredoc → uv run
bun bun heredoc → bun run
ts typescript heredoc → tsx
node node heredoc → node
deno deno heredoc → deno run
py python heredoc → python3
perl perl heredoc → perl
ruby ruby heredoc → ruby
lua lua heredoc → lua

mkApps ships binaries for 6 langs; py/perl/ruby/lua have no binary builder but run fine as task/script bodies.

Block options

Language-specific options attach per-block by calling the block. packages is global only (per-block throws). nixx.app { … } block is a back-compat helper that does the same thing.

bash

option type default description
strict bool true set -euo pipefail preamble (delegated to writeShellApplication).

uv (python-uv)

option type default description
projectRoot path | null null Dir with pyproject.toml + uv.lock; uv run --frozen resolves from it. Preferred over requirements.
requirements [ str ] [ ] Inline PEP 723 deps for one-off scripts. Ignored when projectRoot is set.
pythonReq str ">=3.11" requires-python constraint in the PEP 723 header.
frozen bool true Pass --frozen (use the lock as-is); false re-resolves.
lintIgnore [ str ] [ ] ruff rule codes to ignore at the build gate.

bun

option type default description
projectRoot path | null null Dir with package.json + bun.lock; deps are baked in at build time.
compile bool true bun build --compile → one self-contained binary. false emits a bun-shebang .ts (runtime auto-install).

node

option type default description
nodeModules drv | null null Derivation providing /lib/node_modules; put on NODE_PATH (Node has no inline-dep mechanism).
syntaxCheck bool true node --check build gate.

ts (typescript)

option type default description
nodeModules drv | null null Derivation providing /lib/node_modules (NODE_PATH); tsx runs the .ts directly.

deno

No language-specific options — declare deps inline via npm: / jsr: import specifiers.

writers · mkApps

mkApps { … } { name = block; … }

Global options (first attrset) apply to every app. The block's __lang dispatches to a builder.

global options

option type default description
packages [ drv ] [ ] Global — adds each pkg's /bin to PATH for every app. Per-block packages throws; set it here.
vars attrset { } Nix values spliced into bodies via @nix(…) markers.

dispatch (lang → builder)

__lang builder extra options picked
bash writeBashApplication strict
python-uv writeUvApplication projectRoot, frozen, requirements, pythonReq, lintIgnore
bun writeBunApplication projectRoot, compile
node writeNodeApplication nodeModules, syntaxCheck
typescript writeTsxApplication nodeModules
deno writeDenoApplication (none — inline via npm:/jsr:)

returns

option type default description
{ name = drv } attrset Each attr is a store binary at /nix/store/…/bin/<name>; attr name = binary name.

writers · mkTasks

mkTasks { … } { name = block | task {…} block; … }

A just-style runner. One bash process, so an export in an early task persists into later ones; cwd and shell options reset at each task's entry.

options

option type default description
name str "tasks" Runner binary name (also the bash completion function name).
packages [ drv ] [ ] Global — baked into the runner's runtimeInputs and re-exposed on the devShell/extendShell prompt. Single source of truth (see README).
inputsFrom [ drv ] [ ] Other derivations whose stdenv setup hooks + build inputs apply to the dev shell — for tools that need an env/stdenv hook, not just a binary on PATH.
vars attrset { } Nix values for @nix(…) markers.
env attrset { } Exported in every task body.
envCheck bool false Global default for every bash task: abort before a body runs if a required env var is unset/empty. false = check only with --env-check; true = always. Per-block overrides; --env-list <task> prints needs without running.
defaultDeps [ str ] [ ] Task names run before every task; the default-dep tasks themselves are exempt (no loop).

returns

option type default description
runner drv writeShellApplication (shellcheck-gated) — nix run .#<name>.
devShell mkShell Runner + packages + a bash tab-completion hook for all task names.
extendShell shell → mkShell Merge the runner + packages + hook into your shell.
tasks attrset name → block (each carries .text, .env, .cwd, .deps, …).
meta [ … ] [{ name, text, file, line, indent, description, group }] — feeds linter source-mapping.

Per-task options

sh ''…'' { deps = [ … ]; env = { … }; cwd = ./d; }

Task options ride on the block itself — the same block ''…'' { … } call that attaches language options in mkApps. There is no separate task wrapper. Per-task packages throws (use the global). Positional args reach bash bodies as $@; non-bash bodies get them via env.

options

option type default description
description str | null null One-line summary shown by --list.
group str | null null Groups tasks under a header in --list output.
deps [ str ] [ ] Prerequisite task names (just-style; each runs at most once per invocation).
env attrset { } Exported before the body; merged with the runner's global env, per-task wins on conflict.
cwd path | null null Working dir. The runner resets to the invocation dir, then cds here — a dep's cwd never leaks in.
envCheck bool (global) Override the runner's envCheck default for this task: true = always check, false = only with --env-check.

lib · mkTasks (pure)

nixx.mkTasks { … } { name = block; … }

No pkgs, no packages option, no devShell — use it when you only need the runner script text or a body's .text.

options

option type default description
name str "tasks" Same semantics as the pkgs-bound mkTasks option.
vars attrset { } Same semantics as the pkgs-bound mkTasks option.
defaultDeps [ str ] [ ] Same semantics as the pkgs-bound mkTasks option.
env attrset { } Same semantics as the pkgs-bound mkTasks option.

returns

option type default description
tasks attrset name → block.
runner str The bash runner as a script string (no derivation — no pkgs).
meta [ … ] Source-mapping metadata.

lib · mkScript / mkScripts

nixx.mkScript { … } block  ·  nixx.mkScripts { … } { name = block; … }

A standalone mkScript is evaluated (a bare ${VAR} needs ''$); mkScripts source-reads, so it pays zero ${} tax.

mkScript options

option type default description
lang str | null null Overrides the block's __lang; falls back to bash.
vars attrset { } @nix(…) values.
shebang str | null null Overrides the lang profile's shebang.
strict bool | null null set -euo pipefail (bash profile default true; null → profile).
packages [ drv ] [ ] bash only — exported as PATH. Ignored for non-bash langs.
requirements [ str ] [ ] uv — PEP 723 inline deps.
pythonReq str | null null uv — requires-python.

mkScripts options

option type default description
lang str "bash" Applied to every script in the set.
vars attrset { } @nix(…) values.

Returns { scripts, meta }scripts is name → text; meta feeds the linter remap.

Vars markers

Splice an actual Nix value into a source-read body — native ${…} does not run there. Values come from vars = { … } on mkApps/mkTasks/mkScript.

option type default description
@nix(name) raw toString of the Nix value, spliced verbatim — for paths / derivations / numbers.
@sh:q(name) bash POSIX single-quoted shell literal (shq) — for arbitrary strings. Pass values into a non-bash body via env instead.
(a path value) store Auto-imported into the store (reproducible; exec bit preserved).

shellint

nix run nixx#shellint -- ./  ·  (for pkgs).shellint { src = ./.; … }

Source-driven static lint (no eval): tree-sitter-nix locates every bash ''…'' block and runs three block-scoped passes. It's the static half of the pair — the runtime sibling is the envCheck option above.

passes

option type default description
nix-boundary fatal Shell-only expansions that break Nix (${`{#x}`} ${`{x[@]}`} ${`{x^^}`} …) must be ''${`{…}`}; a bare ${`{VAR}`} with no enclosing with fails Nix eval. Escaped ''${`{…}`}, with-scoped ${`{VAR}`}, and real Nix interpolations are skipped.
shellcheck fatal The bash body (function-wrapped, so local is valid) is shellcheck'd; @nix()/@sh:q() markers are expanded to placeholders first. SC2154/SC2153 (external env) and SC2329 (the wrapper) excluded by default; more via excludeShellChecks.
env warn Lists the external env each block requires (block-bound names subtracted). Never fatal.

config (check builder)

option type default description
src path Tree (or file) to lint; dirs are walked for *.nix.
exclude [ str ] [ ] find(1) path globs to skip.
passes attrset { all = true } Toggle passes: { nix; shellcheck; envcheck; }.
excludeShellChecks [ str ] [ ] Extra shellcheck codes to ignore.

--fix

nix run nixx#shellint -- --fix ./ auto-fixes the nix-boundary both ways: escapes a shell-only ${#x}/${x[@]} to ''${…}, and de-escapes an ''${VAR} back to ${VAR} (only inside a with). Edits in place (--dry-run shows a diff); each file is re-parsed and reverted if it isn't ERROR-free, so a mis-fix can't corrupt it. --fix is app-only — the check stays read-only.

for pkgs

option type default description
inputs.nixx.lib.for pkgs attrset lib + writers(pkgs) + pkgs in one set, for with inputs.nixx.lib.for pkgs; — the one canonical entry point. The single line of ceremony that un-prefixes the constructors and defers Nix's static undefined-variable check (any with makes the scope dynamic), so a bare ${`{VAR}`} survives the source-read.