feat: add docker support - #268
Conversation
|
I came across this repo from an LinkedIn post and was wondering to to run it locally. While I was struggling to find a Dockerfile I was not able to find it. Thought of adding it but then looked at your PR! |
|
I was also looking for a containerized version of this software and stumbled upon this pull request. It was indeed as simple as running This pull request actually offers two things:
Already having a container image that builds automatically with each commit and is automatically pushed as release with each official release is a huge win already. Where possibly an example of the |
|
Keeping this open as the Docker track, but the current 11-line image is a development proof rather than a production container. A current-main revision should verify the GitHub package dependency installs on Alpine, use a multi-stage build with a non-root runtime, copy only runtime output/dependencies, add a healthcheck, and document required build/runtime env. Please include the exact docker build and run commands plus an /api/health result. That evidence will also let us decide whether Next standalone output is worth enabling. |
Aymericr
left a comment
There was a problem hiding this comment.
Thanks for this, and sorry for the long silence — it's been open since April and that's on us. I built and ran it end to end, and the core is solid: docker build --no-cache succeeds on both arm64 and amd64 (5/5 turbo tasks), the container boots next start on :3000, /api/health returns {"status":"ok","app":"editor"}, / renders with the real compiled Tailwind bundle, and docker compose config validates. Every functional claim in your body reproduces.
It also settled two things I'd asked about back in July, both in your favour: the github:pascalorg/plugin-trees dependency does install cleanly on Alpine, and the gnu-pinned native optionalDependencies do not break musl — bun installs both variants and musl resolves at runtime. Good to have that on the record.
One item I'd call a genuine bug rather than polish, and it's the reason I can't merge as-is:
Saved scenes are lost on docker compose down. The editor persists to SQLite, and the default path resolution ends at $HOME/.pascal/data/pascal.db (packages/mcp/src/storage/sqlite-scene-store.ts:107). Inside this container that's /root/.pascal/data/pascal.db, and docker-compose.yml declares no volume — so recreating the container silently discards every project. That's the worst outcome for exactly the "one command to try it" audience this PR is for.
The fix is small, because the store already supports an override (sqlite-scene-store.ts:93-94):
services:
editor:
environment:
NODE_ENV: production
PASCAL_DATA_DIR: /data
volumes:
- pascal-data:/data
volumes:
pascal-data:Using PASCAL_DATA_DIR rather than mounting over /root also keeps the path stable if the runtime user changes — which brings me to the rest, in priority order:
- Volume +
PASCAL_DATA_DIR, as above. This is the blocker. - Don't run as root. The
oven/bunbase already ships abunuser (uid 1000), soUSER bunis enough — and it composes with (1), since the data dir is then explicit rather than$HOME-derived. - Multi-stage. Single-stage means the 2.33 GB image carries ~1.2 GB of dev dependencies (biome, turbo, typescript, tsgo) into the runtime layer. A multi-stage build with Next's
output: 'standalone'came out at 598 MB from this same tree and served identically — 4× smaller. This answers the standalone question I raised in July: worth doing. Noteapps/editor/next.config.tsdoesn't setoutputtoday, so that's part of the change. - Drop
RUN touch apps/editor/.env.local(line 6). It was a valid workaround at your base commit, when the build script read-e ./.env.local, but main has since moved todotenv -e ../../.env.local(apps/editor/package.json:8) — so that file isn't the one read, and dotenv-cli tolerates a missing one regardless. I removed it and the build still completed 5/5.
Two corrections while I'm here, neither blocking:
- The body says optional env vars "can be passed under the
environmentkey". ForNEXT_PUBLIC_*that isn't true — Next inlines those at build time. I ran the image with-e NEXT_PUBLIC_APP_URL=http://runtime-injected.testand the value appears nowhere in the served HTML or client chunks. Those needARG+--build-arg. Worth fixing in the body so nobody debugs it later. NEXT_PUBLIC_GOOGLE_MAPS_API_KEYis a stale variable — it only exists inSETUP.md:26and.env.example:4and is referenced by zero lines ofapps/orpackages/. Not your fault; I'll clean that up separately.
And one thing that isn't a defect but compose should guard against: /scenes returns 500 when the published port differs from 3000, because apps/editor/app/scenes/page.tsx:8-18 derives its self-fetch base from the Host header. Your 3000:3000 mapping avoids it, but setting NEXT_PUBLIC_APP_URL in compose would keep remapped ports and reverse proxies working.
Last thing: the branch is now ~3.5 months behind, and CI landed after you opened this, so it has never run here — 0 check-runs on 5dfca40. Please rebase onto main when you pick this up; bun run check, bun run check-types and bun run test are all gating now.
I'd like to land this — it's a real gap and two people in the thread have asked for it. If you'd rather not do the multi-stage part, I'll take (1), (2) and (4) alone and do the size work myself in a follow-up; say the word. If you've moved on entirely, tell me and I'll carry it over the line with credit to you.
Three problems kept the image from being usable: - Saved scenes went to $HOME/.pascal/data inside the container layer, so `docker compose down` silently discarded every project. Set PASCAL_DATA_DIR and back it with a named volume. - The container ran as root. The base image already ships a `bun` user. - `next build` runs under `node`, and oven/bun's `node` is a shim that re-execs bun. Next 16's build crashes it on both arm64 and amd64 — segfault on bun 1.3.14, a turbopack CommonJS error on 1.3.0. Install real nodejs. CI never hit this because runners have their own node. Also pins the base image to the bun version in `packageManager` and drops the `touch apps/editor/.env.local` workaround, which no longer matches the path the build script reads. Co-Authored-By: Claude Opus 5 <[email protected]>
5dfca40 to
b9d7266
Compare
|
I've carried this over the line, as offered above — pushed to your branch ( While verifying, I found a fourth problem that neither of us had spotted, and it's the one that would have bitten every user: the image doesn't build against current
Next 16's build crashes it. On the version I'd bumped to: and on your original I confirmed it's the runtime and not the platform by reproducing on both arm64 and amd64, then fixing it with one line — Not your fault — Next moved under the branch during the four months this sat open. But it does mean the What's in my commit
What I left out, and whyThe multi-stage / I also dropped a Identical, because the value is frozen at Verified
Thanks for opening this and for answering the Alpine and musl questions back in July — both landed in your favour, and the base image choice is yours, unchanged. Merging once CI is green. Sorry it took us three months to meet you halfway. |
Documented in SETUP.md and .env.example, referenced by zero lines of apps/ or packages/ — there is no geocoder in this app, so the address search it promises does not exist. Noticed while reviewing #268. Co-authored-by: Claude Opus 5 <[email protected]>
Docker support landed in #268 with no mention in SETUP.md, so the only way to find it was to notice the compose file. Records the port constraint too, since remapping it 500s the /scenes page for a non-obvious reason. Co-authored-by: Claude Opus 5 <[email protected]>
Summary
Dockerfileusingoven/bun:1.3.0-alpinethat installs dependencies, builds all workspace packages via Turbo, and serves the Next.js appdocker-compose.ymlfor a one-command start (docker compose up --build).dockerignoreto excludenode_modules, build artifacts, and local env files from the build contextUsage
The editor will be available at
http://localhost:3000.Optional env vars (e.g.
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY) can be passed under theenvironmentkey indocker-compose.yml— the editor works without them.Test plan
docker compose up --buildcompletes without errorshttp://localhost:3000Note
Low Risk
Packaging and ops-only changes; no application auth or business logic modified, though build/runtime assumptions (Bun version, port 3000, data volume) affect how the editor is deployed.
Overview
Adds containerized deployment for the Next.js editor so it can be built and run with
docker compose up --build.The Dockerfile uses
oven/bun:1.3.14-alpine, installs deps withbun install --frozen-lockfile, builds only the editor via Turbo, and runs as thebunuser fromapps/editor. It installs Alpinenodejssonext builduses a real Node binary (the Bun image’snodeshim breaks Next 16). Scene SQLite data is directed toPASCAL_DATA_DIR=/datawith a declared volume and permissions for the runtime user..dockerignorekeeps.git,node_modules, Next/Turbo outputs, env files, and logs out of the build context.docker-compose.ymlmaps host port 3000 to container 3000 (documented constraint for/scenesandNEXT_PUBLIC_APP_URLbuild-time inlining), sets production env andpascal-datavolume on/data, and usesrestart: unless-stopped.Reviewed by Cursor Bugbot for commit b9d7266. Bugbot is set up for automated code reviews on this repo. Configure here.