---
title: Changelog
description: Every notable change to Acropolis by release, from the repository's CHANGELOG.md.
sidebar:
  icon: history
---

:::caution[Experimental]
Acropolis is at `0.x`: minor releases can change flags, output and defaults. Read the entries between your version and the new one before upgrading. Only the latest `0.x` release gets security fixes.
:::

All notable changes to Acropolis. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [semantic versioning](https://semver.org/). Since 0.1.0 the entries are generated by release-plz from PR titles ([Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)). The source is [`CHANGELOG.md`](https://github.com/olimpiacloud/acropolis/blob/main/CHANGELOG.md), and binaries are on the [releases page](https://github.com/olimpiacloud/acropolis/releases).

## [0.3.1](https://github.com/olimpiacloud/acropolis/releases/tag/v0.3.1) - 2026-10-14

### Images

- The `node_modules` layer no longer has a dir twice: a package with nested dependencies (`node_modules/debug/node_modules/ms`, `@mastra/core`, `@types/pg` in a bun app) was written as its own dir and again as the ancestor of the nested one. `docker load` and the containerd image store accept that, but `docker pull` on overlay2 fails with `duplicates of file paths not supported`.
- bun packages marked `bundled` (shipped inside their parent's tarball, like `napi-wasm` in `@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's `node-tanstack-start`.
- A package tarball that names a file twice (`package/./dist/cjs/index.js` and `package/dist/cjs/index.js` in `@rollup/plugin-alias` 5.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 pull` makes on overlay2, since the local Docker uses the containerd image store. `tests/suites/layers` builds a bun and an npm app with a nested dependency.

## [0.3.0](https://github.com/olimpiacloud/acropolis/releases/tag/v0.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 `tsconfig` `extends` of 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 found` on a shared `--home`.
- The reused `node_modules` of an app cache and the cached `node_modules` layers 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 no `libc`, so the package name decides, as it already did with a lockfile.
- Without a lockfile, the `package.json` files 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 cached `node_modules` layer, and ran with the wrong packages.

### Output

- `info.json` has `watchPaths`: 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.json` and 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 with `serde_norway` instead of `serde_yaml`, whose `unsafe-libyaml` is unmaintained (RUSTSEC-2024-0449).

## [0.2.1](https://github.com/olimpiacloud/acropolis/releases/tag/v0.2.1) - 2026-10-09

### Packaging

- Builder image ~30 % smaller to pull (573 → ~400 MB compressed for amd64): the toolchain archives that `acropolis prewarm` leaves in the store are removed; builds only use the extracted toolchains.

## [0.2.0](https://github.com/olimpiacloud/acropolis/releases/tag/v0.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, `/tmp` and `/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-version` of 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_modules` layers.
- `--info` includes `errorClass` and `exitCode`; 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](https://github.com/olimpiacloud/acropolis/releases/tag/v0.1.0) - 2026-10-08

First public release.

### Image building

- A single `acropolis` binary with `build`, `plan`, `prewarm` and `cache export|import`. Output to a registry (`-t`), to an OCI tar loadable with `docker 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.lockb` with their official CLIs), hoisting, install scripts, bun and pnpm `patchedDependencies`, 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 without `go.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.json` and `acropolis.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/sys` and `/sys`, minimal `/dev` and 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. `--info` includes `errorClass` and `exitCode`.
- 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 --json` snapshots in `tests/plans`.
