Changelog
Every notable change to Acropolis by release, from the repository's CHANGELOG.md.
All notable changes to Acropolis. The format follows Keep a Changelog and the project uses semantic versioning. Since 0.1.0 the entries are generated by release-plz from PR titles (Conventional Commits). The source is CHANGELOG.md, and binaries are on the releases page.
0.3.1 - 2026-10-14
Images
- The
node_moduleslayer no longer has a dir twice: a package with nested dependencies (node_modules/debug/node_modules/ms,@mastra/core,@types/pgin a bun app) was written as its own dir and again as the ancestor of the nested one.docker loadand the containerd image store accept that, butdocker pullon overlay2 fails withduplicates of file paths not supported. - bun packages marked
bundled(shipped inside their parent’s tarball, likenapi-wasmin@parcel/watcher-wasm) are no longer extracted a second time: every one of their files was in the layer twice. The new layer check caught it in Railpack’snode-tanstack-start. - A package tarball that names a file twice (
package/./dist/cjs/index.jsandpackage/dist/cjs/index.jsin@rollup/plugin-alias5.1.1, a dependency of nitropack) puts it once in the layer, with the contents of the last entry, as extracting it would. - Every layer is checked while it is written: a path that appears twice (file, dir or link) fails the build with exit 70 instead of producing an image overlay2 refuses. Layers cached by 0.3.0 are not reused (the layer cache is keyed by the release).
Security
- rustls 0.23.46 (RUSTSEC-2026-0346, RUSTSEC-2026-0347 and the Brotli certificate decompression advisory against 0.23.45).
Tests
- The e2e checks every layer of every image (base layers too) for duplicate paths, the check
docker pullmakes on overlay2, since the local Docker uses the containerd image store.tests/suites/layersbuilds a bun and an npm app with a nested dependency.
0.3.0 - 2026-10-13
Builds
- Workspace members get the devDependencies of the members they depend on at build time (bun installed only their dependencies: a
tsconfigextendsof a devDependency member failed in Vite and Astro). The runtime image still gets only dependencies. - yarn berry workspace members keep the root
node_modules(or the PnP files) in the image; they were left out and the app could not import its workspace dependencies. - A node toolchain that a plan asking for fewer parts installed first (yarn berry only takes the headers) no longer serves a plan that needs npm: install scripts failed with
node-gyp: not foundon a shared--home. - The reused
node_modulesof an app cache and the cachednode_moduleslayers are keyed by the Acropolis release too: a newer install plan does not reuse what an older release built from the same lockfile. - Without a lockfile, glibc images no longer get the musl builds of native packages (
@next/swc-linux-x64-musl,@img/sharp-libvips-linuxmusl-x64): the registry’s abbreviated metadata has nolibc, so the package name decides, as it already did with a lockfile. - Without a lockfile, the
package.jsonfiles take the lockfile’s place in the step hashes: two such apps on one--home(or one app after changing its dependencies) reused each other’s cachednode_moduleslayer, and ran with the wrong packages.
Output
info.jsonhaswatchPaths: the repo paths, relative to the workspace root, whose changes can change the image (the member, the workspace members it depends on, devDependencies included, and the root’s lockfile,package.jsonand install/toolchain files).["."]when Acropolis cannot narrow it down.
Tests
- New suites: workspace members with a devDependency member (bun, pnpm, npm, yarn 1 and berry), the Next.js deploy tests (
NEXT_TEST_MODE=deploy, Next 15.5.27 and 16.4.0), TechEmpower FrameworkBenchmarks without their Dockerfiles, and the Heroku getting-started apps and Paketo samples. e2e cases can build a subdirectory (directory) and run several HTTP checks against one container.
Security
- YAML (
pnpm-lock.yaml,pnpm-workspace.yaml,package.yaml) is parsed withserde_norwayinstead ofserde_yaml, whoseunsafe-libyamlis unmaintained (RUSTSEC-2024-0449).
0.2.1 - 2026-10-09
Packaging
- Builder image ~30 % smaller to pull (573 → ~400 MB compressed for amd64): the toolchain archives that
acropolis prewarmleaves in the store are removed; builds only use the extracted toolchains.
0.2.0 - 2026-10-09
Security
- Build steps run under a seccomp filter (no new namespaces, mounts, ptrace, keyring or BPF), image steps use
pivot_root, and host steps see the filesystem read-only except their work dir, their app cache,/tmpand/var/tmp. - Redirects to private hosts and https→http downgrades are refused; archive unpacking is capped (32 GiB per archive, 1 GiB per npm package).
- The store detects blobs truncated by a machine crash.
Builds
- Provider precedence matches Railpack (Go, Rust, Python, Java, … win over a
package.json). - Rust: an unpinned toolchain is raised to the highest
rust-versionof the locked crates; sqlx apps build on the host instead of inside the rust image. - Node: pinned versions of built servers run on distroless/cc with the build toolchain’s
node(olimpia-cloud’s web image: 84.5 → 57.1 MB). - pnpm 10 build-script rules, bun workspace member dependencies, yarn 2.x checksums, single-copy
node_moduleslayers. --infoincludeserrorClassandexitCode; non-UTF-8 file names fail early with exit 78.
Packaging
- Release binary 25 MB (ring instead of aws-lc,
codegen-units = 1); multi-arch builder image (amd64 and arm64). - Docs in English.
0.1.0 - 2026-10-08
First public release.
Image building
- A single
acropolisbinary withbuild,plan,prewarmandcache export|import. Output to a registry (-t), to an OCI tar loadable withdocker load(--oci) and a JSON summary (--info); line-delimited JSON events with--events json. - Content-addressed store, checksum-verified downloads, segmented and with duplication of the lagging segment; the base is copied registry to registry by digest and new layers are compressed in parallel.
- Build steps isolated in mount, PID and network namespaces; steps inside the rootfs of official images with overlayfs (Python, Ruby, PHP, Java, .NET, Elixir).
- Per-app caches that survive ephemeral builders (
acropolis cache export|import).
Ecosystems
- Node: own installer for npm, pnpm, yarn 1 and bun (yarn berry and
bun.lockbwith their official CLIs), hoisting, install scripts, bun and pnpmpatchedDependencies, per-platform binary filtering in yarn; Next (forced standalone, Turbopack), Nuxt, Astro, SvelteKit, Remix, React Router, TanStack Start, Angular, Vite (native bundler with Rolldown), Nx and Turborepo. - Go (modules verified against
go.sum,go.work, apps withoutgo.mod), Rust (toolchain from the channel manifest and vendored crates), Python (uv, poetry, pdm, pipenv, pip), Ruby/Rails, PHP/Laravel, Java, .NET, Elixir, Gleam, Deno, C/C++, static sites and scripts. - Small runtimes: distroless for Node, Bun, Go and Rust; official slim images for the rest.
- Compatible with
railpack.jsonandacropolis.json.
Production
- Operator settings (
ACROPOLIS_CACHE_KEY,ACROPOLIS_CACHE_MAX,ACROPOLIS_BUILD_TIMEOUT,ACROPOLIS_STEP_TIMEOUT,ACROPOLIS_BUILD_ID) separated from the app’s. - Hardening of what is processed as root: validated lockfile, layer and config paths, streaming extraction, limits on logs and HTTP bodies, default build timeout.
- Typed exit codes (0, 1, 70, 75, 78) and a Debian 12 builder image in
deploy/builder. - Security audit (D22): host steps with their own PID namespace, filesystem read-only except their work directory and their app’s cache, read-only
/proc/sysand/sys, minimal/devand an allowlist of capabilities; repo reads and writes confined to the app; size caps on tar, Go zips, crates and registry; registry credentials sent only to their host.--infoincludeserrorClassandexitCode. - Release binary without symbols (31 MB) and MSRV 1.96.
Verification
- 154 of 156 cases of the Railpack examples, 8/8 of the Next.js suite and 37 of 73 Nixpacks cases;
acropolis plan --jsonsnapshots intests/plans.