Submit an issue View all issues Source
MIR-1248

Move the Go buildpack to a glibc/bookworm base (align with other stacks, unblock cgo)

Done runtime Improvement public
phinze phinze Opened Jun 22, 2026 Updated Jun 29, 2026

Context

Go is the only language stack still building on alpine/musl. Every other stack is already debian/glibc:

stack BaseDistro() build image
Go alpine golang:<v>-alpine
Python debian python:<v>-slim
Ruby debian ruby:<v>-slim
Node debian node:<v>-slim
Bun debian (debian)
Rust debian (debian)

So this isn't a scary platform-wide migration to glibc, it's removing Go's one-off inconsistency. The team already accepted glibc's tradeoffs for every other language.

Why

musl is where a class of compatibility problems live, and glibc is the lingua franca of the prebuilt-binary world (manylinux Python wheels, Node prebuilt native addons, prebuilt CLIs/ML runtimes, vendored static libs). Miren already banked most of that win by putting Python/Ruby/Node on debian. The remaining musl tax is paid only by Go, and cgo is the most visible symptom:

  • Source-compiled cgo (e.g. mattn/go-sqlite3) fails today because the builder has no C toolchain and effectively CGO_ENABLED=0.
  • Prebuilt-glibc cgo (e.g. github.com/duckdb/duckdb-go/v2, which vendors a glibc static archive) can't link against musl at all — this is the koikonom/jobsv2 case that kicked this off. Error: build constraints exclude all Go files in …/duckdb-go-bindings/lib/linux-amd64.

Moving Go to bookworm makes both just work, with no app.toml flag and no cgo-detection machinery.

Proposal

Build the Go stack on golang:<v>-bookworm (publish to oci.miren.cloud), with a C toolchain available, so cgo works when the code needs it. Switch GoStack.BaseDistro() to "debian" so the existing apt-vs-apk augmentation machinery applies.

Protect the tiny-image superpower: keep the final runtime stage adaptive. Pure-Go (cgo off) should still emit a static binary on distroless/scratch, exactly as small as today; only actual cgo apps land on debian-slim at runtime. Do NOT regress image size for the 99% pure-Go case by naively running everything on full debian.

Scope / risks

  • Publish + maintain golang:<v>-bookworm images.
  • Flip GoStack.BaseDistro() and adjust pkg/stackbuild/golang.go (toolchain present; adaptive final stage; ensure static binaries still produced for cgo-off).
  • Test: rebuild the Go testdata/ apps + blackbox suite, confirm static-binary output for pure-Go, eyeball image-size deltas.
  • Slightly heavier build/cache image.

No new long-lived surface area to maintain — the appeal is that it deletes an inconsistency rather than adding a feature.

Current workaround

A hand-written Dockerfile.miren on a golang:1.x-bookworm base with CGO_ENABLED=1 builds and runs duckdb cleanly (verified locally during the jobsv2 debugging session). That stays the escape hatch until/unless this lands.

Note

Touches "what's our buildpack base philosophy," so this may warrant an RFD before implementation. Filing as an issue first to decide RFD-vs-build from here.