The dependency and build stages stay on node:22-trixie-slim, where pnpm
picks the glibc native packages. The runner moves to wolfi-base, pinned
by its index digest: glibc, about fifty packages, and every one of them
known to the image scan, Node and the PostgreSQL client included.
nodejs-22, tzdata and postgresql-18-client come from apk, so the pgclient
stage and its pin guard go. The builder writes its Node module ABI and
glibc version out and the runner refuses to build on another ABI or an
older glibc. Wolfi's npm is major 12 and runs no install scripts unless
package.json allows them, so the Prisma CLI install names the three
packages that have one, and the build checks that the schema engine file
is there before asking the CLI about it. npm is installed for that step
and removed in the same layer; the check that nothing is left asks a
fresh shell, whose command cache cannot remember the deleted binary.
Every stage now starts from node:22-trixie-slim, pinned by its multi-arch
index digest, so the native modules load their glibc builds. The arm64
musl Skia build needs ARMv8.2 (LSE atomics, RCpc loads) and dies with
SIGILL on an ARMv8.0 core such as the Raspberry Pi 4's Cortex-A72; the
glibc build runs there (#1311).
The runner keeps what it had: tzdata, TZ, the build-time OS upgrade, the
nextjs user (uid 1001, now in group nodejs gid 1001), the backup and
GeoLite2 directories and every build-time assertion. pg_dump and
pg_restore of major 18 come from the PGDG apt repository, whose signing
key is fetched by node and checked against a pinned SHA-256 before apt
trusts it; PATH names the major 18 directory so the binary does not
depend on Debian's version-picking wrapper. The canvas hoist takes the
-gnu binary package by the pinned version and still fails the build on a
mismatch. bookworm-slim was the other candidate; on the day of the
switch it carried a CRITICAL zlib finding that trixie-slim does not.
The guard pinned the npm-installed dotenv in the Dockerfile to a literal,
which is how that install came to trail the app tree by a patch without
anything noticing. It now reads the Prisma and dotenv versions from
package.json and asks the Dockerfile for the same ones, engines included.
The breaking changes in 18 do not reach this repository: nothing preloads
dotenv with -r, nothing reads a .env.vault, and both entry points in use
(the default export in prisma.config.ts and the side-effect dotenv/config
import in the one-shot scripts) keep their behaviour. dotenv/config stays
quiet by default.
What does change is the load message, which now goes to stderr. Prisma
reads prisma.config.ts on every migrate deploy at container start, so
both loads there pass quiet: true rather than adding two stderr lines to
each boot. The image's /opt/prisma-cli install, which the config resolves
dotenv from, moves to the same 18.0.6.