[bldr]docs

Why bldr

A build system where the same inputs always produce the same output, and the cache is a fact rather than a guess.

Most build systems ask you to describe steps and then try to work out what to skip. bldr asks you to describe artifacts. Every artifact is addressed by the hash of its content, so "have we built this already" has an exact answer, and "is the cache stale" is not a question anyone has to ask.

That one decision is what the rest follows from.

What you get

A cache that cannot be wrong. A build step's inputs are content, and its output is content. Same inputs, same output, every time, on any machine. There is no invalidation to tune and no clean to run when something looks off.

Builds that run somewhere else, without ceremony. Work happens in containers on a bldr node. Your machine needs the bldr CLI and nothing else. No toolchain to install per project, no "works on my machine".

One language for the whole thing. Build definitions are TypeScript. Real imports, real types, real editor support. A member that needs another member's output imports it, and that import is the dependency edge.

import { ContainerImage } from "bldr";
import { nodeProject } from "bldr/node-tools";
import nodeImage from "node";

const site = nodeProject({ scope, image: nodeImage, source: member.rootDirectory })
    .build({ outDir: "dist" });

scope.addOutputDirectory("site", site);

The same graph runs your code. A thing bldr built can be served, deployed or kept running, from the same definition that built it. You do not hand an artifact to a second system and hope the two agree about which version is live.

What it costs

Being honest about the trade, because it is a real one.

You need a node. bldr is a daemon that owns a content store and runs containers. That is a machine to look after, and for a single developer building a small project it is more moving parts than a Makefile.

Builds run in containers, so a step needs an image that can run it. There is tooling for the common cases, but a bespoke toolchain is yours to package.

The build language is TypeScript, not a small declarative format. That buys types and composition, and it costs you a language with loops and conditionals in a place some teams would rather keep dumb.

Where it pays off

Repositories where several things are built from one tree and depend on each other. A shared library, three services, a UI, a container image, and a deployment that has to agree with all of them. That is where restating the dependency graph by hand stops being feasible, where cache correctness starts mattering more than cache cleverness, and where "the thing we deployed" needs to be traceable to the exact inputs that produced it.

On this page