apply drops install_command / build_command / is_static — a static monorepo app gets built and RUN as its root package.json, and boots the wrong workspace #63
Labels
No labels
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-triage
ready
release
scope:apply
scope:capture
scope:coolify-api
scope:fleet
scope:manifest
scope:secrets
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/cast#63
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happened
heavy-duty/incubator'slandingresource, freshly created byapplyon the prod box, crash-loops booting the wrong workspace. The logs are not landing serving files — they are the core API server starting inside landing's container:Landing is a static Astro site in an npm-workspace monorepo. It has no
env_templateand no database — correctly. But because three build fields were dropped on create, Coolify auto-detected the build from the repo-rootpackage.json, whose scripts are scoped to the server:So nixpacks installed at root, built every workspace, and Coolify ran the start command —
npm run start -w apps/core— which demandsDATABASE_URLand dies. Thepublish_directorycast did set (/apps/landing-site/dist) is inert, because nothing told Coolify to serve it instead of running a server.The three fields cast cannot express
The working resource on the hand-built box and the cast-created one differ in exactly three settings — every one of which cast has no manifest field for:
is_static(Static site)install_commandnpm cibuild_commandnpm run build -w apps/landing-sitepublish_directory/apps/landing-site/dist/apps/landing-site/dist✓With static on Coolify serves
publish_directoryand never runs a start command; with a workspace-scoped build/install it builds only landing instead of the whole monorepo (and never touches the server that needs env). cast set the one field it models and had no way to set the three that make this app what it is.cast already knows —
draftsays so out loudThis is not a newly-discovered gap.
draft.ts(which reverse-engineers a manifest from a live instance) has a list titled, verbatim:install_command,build_command, andstart_commandare in that list (draft.ts:418-420). So adraftof the working box would have flagged all three as unmappable — and then they were lost when the manifest was authored by hand.is_staticis worse: it is not even in the list, sodraftis silent about it entirely. The comment's own prediction — "silently absent from a rebuild" — is precisely what happened the first time a rebuild actually ran.Why the diff gate reported parity anyway
The manifest was verified against the hand-built box via a field diff, and it came back clean. It came back clean because
is_static/install_command/build_commandare not in cast's diffed field set — the same write-only-field blind spot as #50 (source-commit toggle) and #51 (backup schedules). A field cast neither creates nor diffs reads as zero drift forever, so a manifest can be "verified at parity" while missing the settings that keep the app alive. This is now the third instance of that class; it may be worth a tracking meta-issue for "settings on the live object that apply neither writes nor diffs."Suggested shape
Add to the manifest's
buildblock (nixpacks/static/dockerfile packs):applywritesinstall_command,build_command,is_staticon create, and diffs them (so their drift stops being invisible).static: truewhen a nixpacks app declares apublish_directory— you do not publish a directory from a long-running service — but an explicit field is safer than a heuristic, and Coolify keeps them independent.draftshould map these three out of itsNO_HOMElist into real emitted fields, and learnis_static.static: truewith nopublish_directoryis almost certainly a mistake (nothing to serve) — warn or error.Immediate operator remedy (no code, unblocks prod now)
On the prod
landingapplication, Advanced tab: enable Is it a static site?, set installnpm ci, set buildnpm run build -w apps/landing-site(publish directory is already correct), redeploy. This reproduces the working box's config by hand until the manifest can carry it.Filed off the
heavy-duty/incubatorprod migration. Field values above are from a live side-by-side of the two boxes'landingapplications.