Forgeon Docs

Documentation, guides, and patterns to help you build on Forgeon — from your first deploy to running serious infrastructure.

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)
package.json
{
  "scripts": {
    "build": "npm run build",
    "start": "node server.js"
  }
}

Go

You need go.mod, and a runnable main package.

Python

Use one of:

  • pyproject.toml
  • requirements.txt
  • Pipfile

Java

Use one of:

  • pom.xml (Maven)
  • build.gradle / build.gradle.kts (Gradle)

This prevents “why did it detect that??” moments.

.forgeon.json
{
  "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)
example buildpack env
$BP_NODE_VERSION="22"
$BP_PYTHON_VERSION="3.11"

Port model (Forgeon runtime)

Forgeon injects:

  • PORT → internal port your app must listen on
  • APP_HOST → typically 0.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.

package.json
{
  "scripts": {
    "build": "next build",
    "start": "next start -p $PORT -H 0.0.0.0"
  }
}

And in .forgeon.json:

.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:

package.json
{
  "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 start script (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 start exists (a start script)
  • 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.
  • Use paketobuildpacks/builder:base as 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.