Configuration
TLDR: tix.toml maps file paths to contexts (like @nixos or @home-manager), controlling which stubs get loaded and how module parameters are typed.
tix.toml
Tix auto-discovers tix.toml by walking up from the file being checked. You can also pass --config path/to/tix.toml explicitly.
Contexts
A context tells tix “files matching these paths are NixOS modules (or Home Manager modules, etc.)” so it knows how to type the standard { config, lib, pkgs, ... }: parameter pattern.
[context.nixos]
includes = ["modules/*.nix", "hosts/**/*.nix"]
stubs = ["@nixos"]
[context.home-manager]
includes = ["home/*.nix"]
stubs = ["@home-manager"]
- includes — glob patterns matching files in this context
- excludes — glob patterns for files to exclude even when
includesmatches. Useful when a broad glob likedir/**/*.nixcovers a directory with a few files that belong to a different context. - stubs — which stub sets to load.
@nixosand@home-managerare built-in references to the generated NixOS/Home Manager stubs (requires[stubs.generate]or theTIX_BUILTIN_STUBSenv var)
For example, if most files under common/ are NixOS modules but common/homemanager/ contains Home Manager modules:
[context.nixos]
includes = ["common/**/*.nix", "hosts/**/*.nix"]
excludes = ["common/homemanager/**/*.nix"]
stubs = ["@nixos"]
[context.home-manager]
includes = ["common/homemanager/**/*.nix"]
stubs = ["@home-manager"]
tix init generates excludes patterns automatically when it detects mixed-kind directories.
What contexts do
When a file matches a context, tix automatically types the module’s function parameters. A NixOS module like:
{ config, lib, pkgs, ... }:
{
services.foo.enable = true;
}
Gets config, lib, and pkgs typed according to the context’s stubs, without any doc comment annotations in the file.
callPackage / dependency-injected files
For files loaded via callPackage or import that take a package set as their parameter:
[context.callpackage]
includes = ["pkgs/**/*.nix"]
stubs = ["@callpackage"]
@callpackage derives its types from the built-in Pkgs module (the same one that types pkgs.stdenv.mkDerivation, pkgs.fetchurl, etc.). Parameters not covered by the built-in stubs remain untyped. For broader coverage, generate pkgs stubs and load them via --stubs or the stubs config key — they merge into the Pkgs type alias automatically.
Inline context annotation
You can also set context per-file with a doc comment at the top:
/** context: nixos */
{ config, lib, pkgs, ... }:
{
# ...
}
Project settings
The [project] section configures project-level behavior for both the LSP and tix check.
[project]
includes = ["lib/*.nix", "pkgs/**/*.nix"]
excludes = ["result", ".direnv", "vendor/**"]
- includes — glob patterns for files to include in analysis. When the LSP starts, these files are analyzed in the background and their inferred types become ephemeral stubs available to all open files.
- excludes — glob patterns for files/directories to skip during
tix check. Excluded files are fully skipped from discovery. Hardcoded ignores (.git,node_modules,result,.direnv,target) are always applied.
tix init generates a [project] section with sensible defaults.
Files matching includes are processed in the background after LSP initialization. As each file’s type is inferred, any open files that import it are automatically re-analyzed with the updated type information.
Suppression directives
Tix supports TypeScript-style comment directives for suppressing diagnostics:
# tix-nocheck
Suppresses all diagnostics for the entire file. Place anywhere in the file:
# tix-nocheck
{ config, lib, pkgs, ... }:
{
# This file will not report any type errors
services.foo.enable = 42;
}
# tix-ignore
Suppresses diagnostics on the next line only:
let
# tix-ignore
x = (1 + 2).foo; # no error reported for this line
y = (3 + 4).bar; # this line still reports errors
in
x
Diagnostics
Control the severity of optional diagnostics. Currently the only configurable diagnostic is unknown_type (E014), which fires when a binding has type ?.
[diagnostics]
unknown_type = "hint" # "off", "hint", "warning", or "error" (default: "hint")
The LSP editor settings (tix.diagnostics.unknownType) take precedence over tix.toml when both are set.
Runtime stub generation
Tix can generate full NixOS, Home Manager, and pkgs stubs at runtime on first use. The result is cached in the Nix store and reused on subsequent runs.
[stubs.generate]
nixpkgs = "/nix/store/...-nixpkgs-src"
home-manager = "/nix/store/...-home-manager-src"
Each source can be a direct store path or a Nix expression:
[stubs.generate]
nixpkgs = { expr = "(builtins.getFlake (toString ./.)).inputs.nixpkgs" }
home-manager = { expr = "(builtins.getFlake (toString ./.)).inputs.home-manager" }
- nixpkgs (required) — path to nixpkgs source, or
{ expr = "..." }to evaluate - home-manager (optional) — path to home-manager source; omit to skip HM stubs
On first run, tix invokes nix build to generate .tix stubs from the NixOS option tree, Home Manager options, and nixpkgs package set. This takes 30-60 seconds. Subsequent runs are instant thanks to a lightweight file cache (~/.cache/tix/store-stubs/). Changing either nixpkgs or tix version triggers regeneration.
[stubs.generate] can coexist with manual stub paths:
[stubs]
paths = ["./my-extra-stubs/"]
[stubs.generate]
nixpkgs = { expr = "(builtins.getFlake (toString ./.)).inputs.nixpkgs" }
Resolution priority:
TIX_BUILTIN_STUBSenv var (always wins)[stubs.generate]runtime generation- Compiled-in minimal stubs
Requirements: The tix binary must be installed via Nix (running from /nix/store/...). In dev mode (cargo build), use TIX_BUILTIN_STUBS or nix build .#stubs instead.
Generating tix.toml
Run tix init to automatically generate a tix.toml for your project:
tix init # Generate tix.toml in current project
tix init --dry-run # Preview without writing
tix init --yes # Overwrite existing tix.toml
tix init /path/to/project # Specify project directory
The command scans all .nix files, classifies each by its structural signals (parameter names, body references, attrset keys), and generates context sections mapping file paths to the appropriate stubs. For flake projects, it also auto-detects nixpkgs and home-manager inputs from flake.lock and generates the [stubs.generate] section.
No-module escape hatch
If tix incorrectly treats a file as a module, add this comment to disable module-aware features:
/** no-module */