Buildpacks Builds
Build from source using Cloud Native Buildpacks (Heroku-style). Great for standard apps—no Dockerfile needed.
Buildpacks (Cloud Native Buildpacks) turns your source code into an image by using language “buildpack” plugins that detect your stack and produce a runnable container.
Think of it like: Nixpacks (smart plan) + more standardized ecosystem.
Choose Buildpacks if you want Heroku-like behavior and your repo follows standard conventions. Choose Nixpacks for faster iteration + simpler overrides. Choose Dockerfile when you need full control.
When to use Buildpacks
Use Buildpacks when:
- Your app is “standard” (Node, Go, Python, Java, Ruby, etc.)
- You want proven detection + build cache behavior
- You want something similar to Heroku / Cloud Foundry flows
Avoid Buildpacks when:
- You need special OS packages or complex multi-stage build logic
- Your app needs multiple processes in one container (use Dockerfile or Template)
- You require very custom commands not supported by buildpacks
Repo requirements (must-have rules)
Your app must:
- Bind to
0.0.0.0 - Use the injected
PORT - Be runnable with one main web process
If your server binds to localhost / 127.0.0.1, Forgeon can’t route traffic to it. Bind to 0.0.0.0.
The most important file per language
Buildpacks depends on your repo looking “normal”.
Node / Bun (JavaScript)
You need package.json. Recommended scripts:
build(if applicable)start(required for web apps)
{
"scripts": {
"build": "npm run build",
"start": "node server.js"
}
}Go
You need go.mod, and a runnable main package.
Python
Use one of:
pyproject.tomlrequirements.txtPipfile
Java
Use one of:
pom.xml(Maven)build.gradle/build.gradle.kts(Gradle)
Recommended: add .forgeon.json
This prevents “why did it detect that??” moments.
{
"builder": "buildpacks",
"buildpacks": {
"builder": "paketobuildpacks/builder:base",
"env": {
"BP_NODE_VERSION": "20"
}
},
"runtime": {
"internalPort": 3000,
"healthcheckPath": "/healthz"
}
}What this controls
- Which buildpack builder image is used (Paketo, Heroku-ish builders, etc.)
- Build-time environment variables like language versions
- Runtime defaults like internal port and health path
Common Buildpack env overrides
These vary by buildpack family, but common ones include:
Node (Paketo)
BP_NODE_VERSION— Node version (e.g.20,22)BP_NPM_VERSION— npm version (optional)BP_YARN_VERSION— yarn version (optional)
Python (Paketo)
BP_PYTHON_VERSION— Python version (e.g.3.11)
Java (Paketo)
BP_JVM_VERSION— JVM version (e.g.17,21)
Port model (Forgeon runtime)
Forgeon injects:
PORT→ internal port your app must listen onAPP_HOST→ typically0.0.0.0
So your app should only care about PORT.
Framework recipes
Next.js (Buildpacks)
Buildpacks can run Next.js, but you must ensure a correct start command.
{
"scripts": {
"build": "next build",
"start": "next start -p $PORT -H 0.0.0.0"
}
}And in .forgeon.json:
{
"builder": "buildpacks",
"buildpacks": {
"builder": "paketobuildpacks/builder:base",
"env": {
"BP_NODE_VERSION": "20"
}
},
"runtime": { "internalPort": 3000 }
}Vite
Vite is often better as static output (Template/Static flow). If you must run it:
{
"scripts": {
"build": "vite build",
"start": "vite preview --host 0.0.0.0 --port $PORT"
}
}Debugging Buildpacks deployments
Deploy builds but runtime fails to start
Common causes:
- Missing
startscript (Node) - Server binds to
localhost - Start command is dev-mode (hot reload, not a server)
- Wrong language version
What to check:
- Build logs: detected language + selected buildpack(s)
- Release output: generated process types (web)
- Runtime logs: actual start command executed
“No web process found” / “process type web missing”
That means Buildpacks didn’t find a runnable “web” process.
Fix by ensuring:
- Node:
npm startexists (astartscript) - Python: a WSGI entry exists (depends on framework)
- Go: main produces a binary and is runnable
Common gotchas
- Monorepo: Buildpacks often assume repo root. If your app lives in a subdir, prefer Template or Dockerfile unless you support workdir config.
- Multiple services: One buildpack build produces one image. If you need worker + web, deploy them as separate services.
- Native deps: If you need OS packages, Dockerfile is usually the cleanest.
Recommended defaults
- Use
paketobuildpacks/builder:baseas a safe general-purpose builder - Pin language versions via buildpack env (
BP_NODE_VERSION, etc.) - Always bind to
0.0.0.0:$PORT
Buildpacks love “boring repos.” If your repo is boring, your deploys will be exciting—in a good way.