perf: slim the Docker image (turbo prune multi-stage + cap-media layer fix) - #49
Merged
Merged
Conversation
…cap-media dup The self-host image had grown to ~8.5GB (uncompressed). Two causes: 1. `COPY docker/cap-media/ /tmp` then extract + `rm` left the ~430MB tarball baked into an immutable layer (the rm only hid it). Now bind-mounted for the extract RUN, so the archive is never a layer — only the extracted media ships. 2. `pnpm install` ran at the workspace root with no scoping, installing every app's deps (tv-native/Expo, tv-tauri, desktop, site, mcp, roku, promo) into the image. Now a multi-stage build runs `turbo prune server web tv-web --docker` and installs only that dependency closure. web/tv-web keep their dev toolchain on purpose (they vite-build at container startup); the server bundle is still built once here. Runtime behavior is unchanged (same CG_ROLE server/web/tvweb entrypoint). Dev/local workflows are untouched — the prune only happens inside the image build.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Quixomatic
marked this pull request as draft
September 26, 2026 02:30
Quixomatic
marked this pull request as ready for review
September 26, 2026 17:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #48.
The self-host Docker image had grown to about 8.5GB on disk. There were two causes, both confirmed against the Dockerfile.
The first is a baked cap-media duplicate, about 438MB. The Dockerfile did
COPY docker/cap-media/ /tmp, extracted it, thenrm'd the copy. Docker layers are immutable, so thatrmonly hides the ~430MB tarball; it stays in the layer. It's now bind-mounted for the extract step instead, so the archive is never a layer and only the extracted media ships. This has been in every image since v0.6.27.The second is the root
pnpm install, about 4GB. It ran unscoped, installing every workspace app's dependencies (tv-native/Expo, tv-tauri, desktop, desktop-setup, site, mcp, roku, promo), none of which run in the container. The build is now multi-stage and runsturbo prune server web tv-web --docker, so it installs only what those three roles need.What changed
turbo prune), a build stage (pruned install, Prisma generate, server build), and a final runtime stage.--mount=type=bindinstead ofCOPYplusrm.docker/cap-media.What didn't change
Same base (Bun and pnpm), same lockfile-pinned dependency versions for the three roles, same Prisma client, same
tsdownserver bundle and.well-knownworkflow handlers, same cap-media (39 files), same entrypoint andCG_ROLEbehavior. web and tv-web still build with Vite at startup. Local dev is untouched; the prune only happens inside the image build.Results
Compressed pull from the GHCR manifests, amd64:
0.14.61COPY . ./tmpdupAbout 58% smaller compressed (2.5GB to 1.04GB), and roughly 70% on disk (8.5GB to about 2.2 to 2.6GB). The remaining ~1GB is cap-media, which is already-compressed video and won't shrink, plus the Vite toolchain that web and tv-web need to build at startup.
The CI multi-arch build passed, and the image was run on a real TrueNAS/Dockge stack: all three roles, the startup migrate, both startup Vite builds, and the cap-media diagnostic.
A separate follow-up, not in this PR: defaulting cap-media to an on-demand fetch (like the desktop supervisor) would drop the last ~437MB.