11# files
22
3+ [ ![ Nix Flake Check] ( https://github.com/sini/files/actions/workflows/check.yaml/badge.svg )] ( https://github.com/sini/files/actions/workflows/check.yaml )
4+ [ ![ License: MIT] ( https://img.shields.io/badge/License-MIT-blue.svg )] ( https://opensource.org/licenses/MIT )
5+
36A [ flake-parts] ( https://flake.parts ) module for managing in-repository
47generated files. Declare file contents in Nix, write them with one command,
58and verify they stay in sync via ` nix flake check ` .
69
7- Fork of [ mightyiam/files] ( https://github.com/mightyiam/files ) .
10+ This project is an independent, hard fork of
11+ [ mightyiam/files] ( https://github.com/mightyiam/files ) . It is maintained entirely
12+ separately and has no affiliation with, nor is it endorsed by, the original
13+ author.
14+
15+ ## Table of Contents
16+
17+ - [ files] ( #files )
18+ - [ Table of Contents] ( #table-of-contents )
19+ - [ Motivation] ( #motivation )
20+ - [ What this fork adds] ( #what-this-fork-adds )
21+ - [ Quick start] ( #quick-start )
22+ - [ With treefmt] ( #with-treefmt )
23+ - [ With derivation sources] ( #with-derivation-sources )
24+ - [ In a monorepo] ( #in-a-monorepo )
25+ - [ API reference] ( #api-reference )
26+ - [ ` files.file ` ] ( #filesfile )
27+ - [ ` files.treefmt ` ] ( #filestreefmt )
28+ - [ ` files.formatters ` ] ( #filesformatters )
29+ - [ Formatter priority] ( #formatter-priority )
30+ - [ ` files.files ` (list API)] ( #filesfiles-list-api )
31+ - [ Other options] ( #other-options )
32+ - [ Without flake-parts] ( #without-flake-parts )
833
934## Motivation
1035
@@ -17,13 +42,13 @@ it across [den](https://github.com/denful/den)'s template ecosystem:
1742 flake-parts modules.
1843- ** Adopted experimental Nix features** — the ` |> ` pipe operator requires
1944 ` extra-experimental-features = [ "pipe-operators" ] ` in every consuming
20- flake's ` nixConfig ` . We prefer stable Nix .
45+ flake's ` nixConfig ` . This created additional user friction .
2146- ** Renamed ` path_ ` to ` path ` without alias** — a breaking change with no
22- migration path for existing consumers.
47+ migration path or notification for existing consumers.
2348- ** No convenience API** — the list-of-` {path, drv} ` interface requires
2449 boilerplate for the common case of writing text or copying a file. NixOS has
2550 had ` environment.etc ` -style attrset APIs for years.
26- - ** No multi-flake support** — the writer hardcodes
51+ - ** No multi-flake support** — the writer hardcoded
2752 ` git rev-parse --show-toplevel ` with no way to target a subdirectory,
2853 making it unusable in monorepos.
2954- ** Eager eval breaks ` --no-build ` ** — ` lib.readFile ` at evaluation time
@@ -46,7 +71,8 @@ it across [den](https://github.com/denful/den)'s template ecosystem:
4671- ** Multi-flake repo support** — ` relativeRoot ` for monorepo sub-flakes
4772- ** Lazy checks** — ` nix flake check --no-build ` works on fresh clones
4873- ** Backwards compatibility** — ` path_ ` and ` gitToplevel ` aliases
49- - ** No experimental features** — ` |> ` replaced with ` lib.pipe `
74+ - ** Stable Nix syntax** - The experimental ` |> ` operator is replaced with
75+ ` lib.pipe ` , so you don't need to enable ` pipe-operators ` in your nixConfig.
5076
5177## Quick start
5278
@@ -123,7 +149,6 @@ formatter pass through unchanged.
123149 # no formatter matches .txt — passes through unchanged
124150 files.file."LICENSE".text = "MIT";
125151
126- packages.write-files = config.files.writer.drv;
127152 };
128153 };
129154}
@@ -179,14 +204,14 @@ All options live under `perSystem.files`.
179204Attrset of files to manage. The attribute name is the file path relative to
180205the project root. Use slashes for subdirectories.
181206
182- | Option | Type | Default | Description |
183- | -------------- | -------------------------------| ---------| ----------------------------------------------------|
184- | ` enable ` | ` bool ` | ` true ` | Set ` false ` to suppress this file. |
185- | ` text ` | ` nullOr lines ` | ` null ` | Inline text content. Sets ` source ` automatically. |
186- | ` source ` | ` path ` | — | Path or derivation for the file content. |
187- | ` executable ` | ` bool ` | ` false ` | ` chmod +x ` after writing. |
188- | ` onChange ` | ` str ` or ` { runtimeInputs, script } ` | ` "" ` | Shell commands run after all files are written. Runs under ` set -euo pipefail ` . |
189- | ` format ` | ` nullOr (name -> drv -> drv) ` | ` null ` | Per-file formatter. Overrides all other formatters. |
207+ | Option | Type | Default | Description |
208+ | ------------ | -- ---------------------------------- | ------- | ------------------------------------------------------------------------------- |
209+ | ` enable ` | ` bool ` | ` true ` | Set ` false ` to suppress this file. |
210+ | ` text ` | ` nullOr lines ` | ` null ` | Inline text content. Sets ` source ` automatically. |
211+ | ` source ` | ` path ` | — | Path or derivation for the file content. |
212+ | ` executable ` | ` bool ` | ` false ` | ` chmod +x ` after writing. |
213+ | ` onChange ` | ` str ` or ` { runtimeInputs, script } ` | ` "" ` | Shell commands run after all files are written. Runs under ` set -euo pipefail ` . |
214+ | ` format ` | ` nullOr (name -> drv -> drv) ` | ` null ` | Per-file formatter. Overrides all other formatters. |
190215
191216``` nix
192217perSystem = { config, pkgs, ... }: {
@@ -220,10 +245,10 @@ perSystem = { config, pkgs, ... }: {
220245
221246### ` files.treefmt `
222247
223- | Option | Type | Default | Description |
224- | ----------- | ----------- | -------------------- | ---------------------------------------- |
225- | ` enable ` | ` bool ` | ` false ` | Format entries through ` nix fmt ` . |
226- | ` package ` | ` package ` | ` config.formatter ` | Treefmt wrapper to use. |
248+ | Option | Type | Default | Description |
249+ | --------- | --------- | ------------------ | --------------------------------- |
250+ | ` enable ` | ` bool ` | ` false ` | Format entries through ` nix fmt ` . |
251+ | ` package ` | ` package ` | ` config.formatter ` | Treefmt wrapper to use. |
227252
228253### ` files.formatters `
229254
@@ -247,28 +272,49 @@ files.formatters.json = name: drv:
247272### ` files.files ` (list API)
248273
249274The original list-based API. ` files.file ` entries merge into this list
250- automatically. Both APIs can be used together.
275+ automatically. Both APIs can be used together. The formatting pipeline
276+ (treefmt, global formatters, per-file ` format ` ) applies to both APIs.
277+
278+ | Option | Type | Default | Description |
279+ | ------------ | ----------------------------- | ------- | ---------------------------------------------------- |
280+ | ` path ` | ` str ` | — | File path relative to project root. |
281+ | ` drv ` | ` package ` | — | Derivation whose output is the file content. |
282+ | ` executable ` | ` bool ` | ` false ` | ` chmod +x ` after writing. |
283+ | ` format ` | ` nullOr (name -> drv -> drv) ` | ` null ` | Per-file formatter. Overrides all other formatters. |
284+ | ` onChange ` | ` { runtimeInputs, script } ` | ` {} ` | Shell commands run after writing if content changed. |
251285
252286``` nix
253287files.files = [
254- { path = "README.md"; drv = pkgs.writeText "README.md" "# Hello"; }
288+ {
289+ path = "README.md";
290+ drv = pkgs.writeText "README.md" "# Hello";
291+ }
292+ {
293+ path = "data/config.json";
294+ drv = pkgs.writers.writeJSON "config.json" { version = 1; };
295+ # per-file formatter works in both APIs
296+ format = name: drv:
297+ pkgs.runCommand "jqfmt-${name}" { nativeBuildInputs = [ pkgs.jq ]; } ''
298+ jq --sort-keys . < ${drv} > $out
299+ '';
300+ }
255301];
256302```
257303
258304### Other options
259305
260- | Option | Type | Default | Description |
261- | ----------------| ------------------| ------------| ------------------------------------------------|
262- | ` root ` | ` path ` | — | Root for check comparisons. Auto-set to ` self ` via flake-parts; set ` root = self; ` in vanilla flakes. |
263- | ` relativeRoot ` | ` str ` | ` "" ` | Subdir from git root for the writer. |
264- | ` generateApp ` | ` bool ` | ` false ` | Expose writer as ` nix run .#write-files ` . |
265- | ` writer.exeFilename ` | ` singleLineStr ` | ` "write-files" ` | Writer executable name. |
266- | ` writer.drv ` | ` package ` | * (computed)* | The writer derivation (read-only). |
267- | ` checks ` | ` attrsOf package ` | * (computed)* | Per-file check derivations (read-only). |
306+ | Option | Type | Default | Description |
307+ | -------------------- | ----------------- | --------------- | ----------------------------------------------------------------------------------------------------- |
308+ | ` root ` | ` path ` | — | Root for check comparisons. Auto-set to ` self ` via flake-parts; set ` root = self; ` in vanilla flakes. |
309+ | ` relativeRoot ` | ` str ` | ` "" ` | Subdir from git root for the writer. |
310+ | ` generateApp ` | ` bool ` | ` false ` | Expose writer as ` nix run .#write-files ` . |
311+ | ` writer.exeFilename ` | ` singleLineStr ` | ` "write-files" ` | Writer executable name. |
312+ | ` writer.drv ` | ` package ` | _ (computed)_ | The writer derivation (read-only). |
313+ | ` checks ` | ` attrsOf package ` | _ (computed)_ | Per-file check derivations (read-only). |
268314
269315## Without flake-parts
270316
271- Use ` module.nix ` directly with ` evalModules ` — no flake-parts dependency:
317+ Use ` files.module ` directly with ` evalModules ` — no flake-parts dependency:
272318
273319``` nix
274320{
@@ -282,7 +328,7 @@ Use `module.nix` directly with `evalModules` — no flake-parts dependency:
282328 pkgs = nixpkgs.legacyPackages.x86_64-linux;
283329 eval = pkgs.lib.evalModules {
284330 modules = [
285- ( files + "/module.nix")
331+ files.module
286332 {
287333 config._module.args = { inherit pkgs; };
288334 config.files.root = self;
@@ -297,3 +343,6 @@ Use `module.nix` directly with `evalModules` — no flake-parts dependency:
297343 };
298344}
299345```
346+
347+ For usage without any flake infrastructure, see
348+ [ ` templates/no-flake ` ] ( templates/no-flake/default.nix ) .
0 commit comments