Home About Documentation Templates Examples Showcase GitHub
Theme

Workflows & patterns · unreleased v4.10

General build systems.

Nift can act as a dependency-aware general build system alongside its website-generation role. Name the artifacts, describe how they are built, and keep specialist tools where they belong.

Development-version workflow.

These examples require the unreleased v4.10 build / depends features. Stable v4.9 does not provide this tracked-item contract.

When this model fits

Use it when a project produces named files through a mix of native Nift processing and external commands: generated data, API descriptions, bundles, manifests, documentation or website pages. Nift can own the build graph without owning every transformation.

Tracked artifacts, not just arbitrary tasks

Each tracked name connects source/content and one declared output. It may carry a custom script, pre/post hooks, completion prerequisites, ordinary file dependencies, minification policy and incremental state. In a custom build, content can be a small recipe descriptor but must exist; the script must produce the tracked output.

tracked source / inputs
         ↓
     pre-build
         ↓
custom build OR Nift render
         ↓
     post-build
         ↓
successful output + metadata

Prerequisite edges form a DAG around those units. Pre and post failures fail the item; failed prerequisites block descendants while independent branches can continue. Output must exist before post runs, and successful metadata is committed after post succeeds.

Completion order and invalidation are different

generated-api → app-js ─┐
styles ────────────────┼→ manifest
images ────────────────┘

depends says which tracked builds must finish first. It does not rebuild a consumer merely because a prerequisite changed. Record the prerequisite output as an ordinary dependency when its bytes affect the consumer. Independent ready branches can run concurrently within the configured worker count. No exact start order is promised.

Normal projects do not need a manually declared DAG for every page. Use depends only where completion order matters; existing file/content dependency tracking continues to handle ordinary incremental builds.

Complete working example

Download the small build-system project. It contains all configuration, inputs, scripts and ordinary dependency sidecars. It uses only native Nift features, so no bundler installation is needed.

unzip build-systems.zip
cd build-systems
nift build --all
nift status -p
nift info --tracking
nift build

The graph is generated-api → app-js → manifest. Its tracked entries are:

{
  "tracked": [
    {
      "name": "generated-api",
      "title": "API",
      "content-ext": ".json",
      "output-ext": ".json"
    },
    {
      "name": "app-js",
      "title": "App",
      "output-ext": ".js",
      "build": "scripts/app.f",
      "depends": [
        "generated-api"
      ]
    },
    {
      "name": "manifest",
      "title": "Manifest",
      "output-ext": ".json",
      "build": "scripts/manifest.f",
      "depends": [
        "app-js"
      ]
    }
  ]
}

scripts/app.f generates a valid classic JavaScript file from the API JSON and explicitly minifies its final text:

fn(read_text(path)) {
    input := file(path)
    input.open("r")
    text := input.read()
    input.close()
    return text
}

source := "const api = " + read_text("public/generated-api.json") + ";\nconsole.log(api.message);\n"
result := minify(source, "js")
if(!result.ok) { throw error(result.error, "build.minify_failed") }
out := file(getenv("NIFT_HOOK_OUTPUT"))
out.open("w")
out.write(result.output)
out.save()
out.close()

scripts/manifest.f serializes a manifest using the completed output:

fn(read_text(path)) {
    input := file(path)
    input.open("r")
    text := input.read()
    input.close()
    return text
}

app := read_text("public/app-js.js")
data := {"app": "app-js.js", "length": app.length()}
out := file(getenv("NIFT_HOOK_OUTPUT"))
out.open("w")
out.write(data.stringify())
out.save()
out.close()

The project includes content/app-js.deps.json with public/generated-api.json and content/manifest.deps.json with public/app-js.js. Change the API message, run nift build, and the byte-dependent consumers can rebuild in the same invocation. Targeted nift build manifest includes its prerequisite closure; clean prerequisites are checked without unnecessary rendering.

Explain what needs building

nift status -p
nift info --tracking
nift info --all
nift build -p

status -p reports incremental reasons without changing output or success metadata. info inspects tracked/project state; it is not a promised graphical DAG viewer. Named artifacts, paths, scripts and explicit edges give people and coding agents a structured configuration to inspect.

Moving a Make/Ninja workflow

Nift overlaps Make/Ninja in prerequisites, incremental checks, custom commands and parallel graph scheduling. For suitable file-producing project graphs it can fill that orchestration role while retaining Nift’s tracked-artifact and website-processing model. This is not a claim of complete feature parity or measured scheduling superiority.

  1. Inventory the actual output artifacts and their source inputs.
  2. Give each declared output a tracked name and appropriate extensions.
  3. Move its command into a native custom build script; retain the compiler or bundler.
  4. Translate completion edges into depends and byte invalidation into ordinary file dependencies.
  5. Check failure propagation, clean/incremental/target builds and output equivalence.
  6. Measure the real project before choosing a replacement.

There is no automatic arbitrary-Makefile converter. Phony tasks, dynamic dependency files, implicit rules, tool-specific caching and multiple-output rules need individual assessment; not every Make/Ninja semantic has a direct equivalent.

From npm scripts and shell sequencing

Keep npm, pnpm or Bun as package managers and tool launchers. A tracked script can call a project’s existing compiler command while depends expresses sequencing between its file outputs. Replace hidden build-css && build-js && make-manifest sequencing with named output units when that makes the project easier to inspect. A package-manager invocation does not automatically expose all of its imported files to Nift: record the real inputs and tool configuration as ordinary dependencies.

Build the asset workflow

See Asset pipelines for CSS, JavaScript, image outputs, explicit final minification and a complete parallel example.

Use tracked.json, Build Scripts, native scripting, ordinary file dependencies, incremental state, build/status/info commands, filesystem APIs and minification for the exact mechanics.