Forgepacks Builds
Build using a Forgeon Template (pre-wired build + runtime rules). Best for monorepos, non-standard apps, or when you want repeatable “golden paths”.
Templates are Forgeon’s opinionated build recipes: a curated set of install/build/start rules (and sometimes OS deps) that produce predictable results.
If Nixpacks is “auto-detect” and Buildpacks is “standard ecosystem,” Templates are: “don’t guess—do exactly this.”
Pick Template when you want repeatable deployments for a framework, monorepo, or stack that needs specific wiring.
When to use Template
Use Templates when:
- Your project is a monorepo (apps in subfolders)
- You need a known-good recipe (Node + Bun, Next.js, Hono, Django, etc.)
- Your runtime needs extra wiring (workdir, custom start, build outputs)
- You want “golden path” deployments across many repos
Avoid Templates when:
- Your app is simple + standard → use Nixpacks or Buildpacks
- You already have a production Dockerfile → use Dockerfile flow instead
What a Template controls
A Template can define:
- workdir (build from
apps/web, not repo root) - install/build/start commands
- runtime port + host binding rules
- required environment variables
- optional OS packages (if your platform supports them)
In other words: Template = Build Plan + Runtime Contract.
Required runtime contract (same as all Forgeon builds)
Your app must:
- Bind to
0.0.0.0 - Use the injected
PORT - Stay alive as the main process (don’t daemonize and exit)
If your server binds to 127.0.0.1, it will work locally and fail remotely. Bind to 0.0.0.0.
Recommended: add .forgeon.json
This is how you tell Forgeon: “Use Template X, and here’s the exact behavior.”
{
"builder": "template",
"template": {
"id": "node-bun-web",
"workdir": ".",
"install": "bun install --no-save",
"build": "bun run build",
"start": "bun run start"
},
"runtime": {
"internalPort": 3000,
"healthcheckPath": "/healthz"
}
}Template fields explained
template.id— which Forgeon recipe to usetemplate.workdir— where to run commands (great for monorepos)install/build/start— explicit commands (no detection)runtime.internalPort— internal port your app listens on
Monorepo example
Repo structure:
Deploy apps/web as a service:
{
"builder": "template",
"template": {
"id": "nextjs-web",
"workdir": "apps/web",
"install": "bun install --no-save",
"build": "bun run build",
"start": "next start -p $PORT -H 0.0.0.0"
},
"runtime": { "internalPort": 3000 }
}Deploy apps/api as a second service with a different template/workdir.
Environment variables (Template builds)
Templates can ship defaults, but you can still override env vars in Forgeon:
- Project → Environment Variables
- Service → Env Overrides
Common ones:
PORT(injected)APP_HOST(usually0.0.0.0)- any framework-specific settings (
DATABASE_URL,JWT_SECRET, etc.)
Template vs Nixpacks vs Buildpacks
Nixpacks: fastest auto-detect + easy overrides
Buildpacks: standardized ecosystem, Heroku-like behavior
Template: explicit recipe, best for monorepo + no guessing
Debugging Template deployments
Runtime fails with “pull access denied … run:latest”
That means Forgeon tried to boot a placeholder image instead of your built artifact.
Most common causes:
- Build step didn’t produce/publish an image
- The boot request had
image_refmissing/empty - A code path overwrote the real image ref during normalization
What to check:
- Build logs: confirm the final image tag and digest
- Deployment DB record: confirm
image_refis present - Runtime logs: confirm
docker run ... REAL_IMAGE_REF
Commands succeed locally, fail on Forgeon
Likely causes:
workdiris wrong (monorepo)- build output path differs (
dist,.next,build) - your start command is dev-mode (e.g.,
bun run dev) - app binds to
localhost
Best-practice recipes
Next.js (production)
Use real production start:
- build:
next build - start:
next start -p $PORT -H 0.0.0.0
API services (Node/Bun)
- start:
bun run start(must bind to0.0.0.0:$PORT)
Vite frontend
Prefer Template → Static Deploy if possible:
- build:
vite build - publish directory:
dist/
If your app is purely static, don’t pay the “runtime tax.” Deploy static.
Recommended defaults
- Always set
template.workdirexplicitly for monorepos - Never use
devcommands for production runtimes - Always bind to
0.0.0.0and usePORT
Templates are the “chef’s menu.” You can still ask for changes—just don’t argue with the oven temperature.