deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

rootstock brings Copier-style project template updates to a single Rust binary

A developer has released rootstock, a Rust reimplementation of Copier that creates projects from git templates and updates them via three-way merge, shipped as a single binary with git as its only runtime dependency.

rootstock brings Copier-style project template updates to a single Rust binary

A single-binary reimplementation of Copier

A developer has released rootstock, a Rust reimplementation of Copier, the Python-based project templating tool. In a post on dev.to, the author — who writes Rust professionally under the handle bodasooqa — describes a tool that creates projects from versioned git templates and keeps them current through three-way merges, packaged as a single binary whose only runtime dependency is git.

According to the post, the motivation is the same convenience that has driven adoption of tools like Biome, Ruff and uv: fast, self-contained binaries with nothing to set up beyond the binary itself. Copier, by contrast, needs Python and pipx present on every machine and CI job that touches a template.

Templates that keep feeding existing projects

Most scaffolding tools — the post names cargo-generate, kickstart and cookiecutter — render a template once, after which the project and the template go their separate ways. That works for a one-off but breaks down when a template keeps evolving: shared CI workflows, lint configurations, or a service skeleton a team uses everywhere. A fix applied to the template never reaches the projects already generated from it.

Copier's answer is to record how a project was created and replay later template changes on top of it, preserving local edits. rootstock implements the same model. Its new command renders a template and writes a .rootstock.toml file alongside the project, capturing the template source, tag, exact commit, the user's answers and the list of files written. The name comes from grafting, where the rootstock feeds a scion that grows its own way: the template keeps feeding projects that diverge from it.

Three-way merge via git

On update, rootstock renders the template twice into temporary directories: the old version with the recorded answers (the base) and the new version with the current answers (the target). It then compares base, target and the actual project file path by path. If only the template changed a file, the template's version is taken; if only the user changed it, nothing happens; if both did, the file goes through git merge-file, the same mechanism Copier uses. The author says the git CLI was chosen over a merge library deliberately, so results match Copier, conflict markers stay familiar, and the user's local git configuration cannot influence the merge.

Cases that cannot be merged are handled explicitly. An edited binary file keeps the user's copy, with the template's version written next to it as name.rootstock-new. A file the user deleted but the template changed stays deleted and is reported. Files marked as starter content, such as a README, are written once and never touched again. Answers can also be changed after generation: update --data ci=false re-renders even when the template version has not moved.

Exit codes designed for CI

Every case that needs a human ends with exit code 2 and one line per problem on stdout, while routine output goes to stderr. The author uses this in a daily workflow attached to each project: run rootstock update, open a pull request, and label it when the exit code signals conflicts. Clean minor and patch updates merge themselves once CI is green; conflicting ones wait for review.

A companion command, rootstock check, runs in CI without network access and fails on leftover conflict markers or side files, so a half-resolved update cannot slip into the main branch. The whole update lands as an ordinary git diff, making it as reviewable and revertable as any other change.

Migration and current limits

rootstock import-copier converts an existing Copier template, a project Copier generated, or both if they share a directory, and writes nothing unless the entire conversion succeeds. Older template versions containing only a copier.yml are read directly by update and converted in memory. The author's acceptance test was byte-for-byte identical rendering against Copier 9.19 for every combination of answers in their own template — a bar met for that template, not a universal guarantee.

At version 0.1.0 the tool covers the subset of Copier its author's own templates use. Copier's _migrations, Jinja extensions and some question types are not implemented, and the importer stops with a full list if a template requires them. Installation is via cargo install rootstock --locked, or prebuilt binaries for Linux (static musl), macOS and Windows on GitHub Releases.

Why it matters

Template drift is a quiet tax on any team sharing scaffolding across projects: fixes land in the template and never reach the code that needs them. Copier demonstrated that treating templates as long-lived dependencies rather than one-off generators solves the problem, but its Python runtime adds setup friction to every machine and pipeline that touches it. rootstock ports that model to a self-contained Rust binary and, notably, designs its failure modes around automation: structured exit codes, offline verification, and updates that arrive as reviewable diffs. It is early — a 0.1.0 release with partial Copier coverage and compatibility verified on a single template — but the core idea, that generated projects should keep receiving template improvements, is now available without a Python toolchain.

  • #rust
  • #developer-tools
  • #templating
  • #open-source
  • #scaffolding

Related posts