theconsensuslabs/noalloc
Developer ToolsChecks a Go call tree for heap allocations and provides fixed-capacity containers and alloc-free JSON helpers.
noalloc is a Go toolchain add-on for teams that have written allocation-free code and want it to stay that way as the code changes. Instead of measuring one test input with testing.AllocsPerRun, it follows the whole call tree from a marked entry point and reports every line it judges can allocate, so allocation becomes a reviewable property rather than a habit. It has been used in production at the author's company, but the README describes it as experimental, AI-written and likely to change substantially.
The check in practice
A function is marked //noalloc:root and the noalloc CLI checks it and everything it calls. Findings name the file, line, function and reason, for example a map write or a string concatenation that escapes; -report adds the call chain that led to the allocation. The tool exits 1 when it finds an allocation and 2 when it could not run. Lines can be exempted with //noalloc:exempt <reason>, and a written exemption list can be compared in review so a widening exemption is noticed.
Three directives shape what counts: //noalloc:fixed marks a type whose methods never grow its slices, //noalloc:append marks an append-like function, and -scratch pkg.Type declares a type's fields as reused memory. Allocations on an error or panic that ends the root call are allowed once per call, as is nil-check first-use setup; a failure inside a loop that keeps going is checked like any other path. Code that already allocates can be adopted incrementally through a baseline file that fails only on new allocations.
The CLI requires Go 1.27 or later. It parses go build -gcflags=-m output, so that output changing between Go releases matters: the README advises pinning the toolchain in go.mod and rerunning after upgrades.
Fixed-capacity containers and codecs
The bounded package (bounded) offers Buf, Vec, Slice and Map with a fixed maximum capacity. Writes past capacity do nothing and mark the container full, so a request can check once at the end. Per-request memory comes from a Region with a budget that borrows chunks from a shared Pool, and releasing the region returns them. The README pairs this with explicit admission planning: reserve only after a request is admitted, size the pool for all admitted requests, and have a plan for exhausting the budget.
The JSON package (encoding/json) uses a jsongen command to generate allocation-free WriteJSON/ReadJSON methods; maps and interfaces are refused. The README reports it as slower than goccy/go-json on its benchmark feed but with zero allocations per feed decode, measured on an Apple M4 with Go 1.27.0 under load, so the figures are comparison-relevant rather than absolute. bounded's pool and map are also documented as slower than sync.Pool and Go's map in exchange for a bounded footprint. Append-style HTML and URL escapers are provided for a subset of html/template's escapers.
Limits worth knowing before adopting
noalloc trusts its allowlist and every exemption without verifying them, and cannot resolve indirect calls through function values; those are reported. Interface calls are checked against every implementation it can find, which can produce false positives such as io.Writer.Write. The cross-check against compiled code has gaps (inlined calls from other packages, unchecked lines, unclassified runtime calls) and sees only one build configuration. First runs on a new toolchain or dependency set are much slower, reported as 39 seconds versus 4.
Licensing is MIT, with portions adapted from Go keeping Go's BSD license (LICENSE).
Written by AI from the project's README, updated October 30, 2026. The project's own docs are the source of truth.