Skip to main content
Cloud Native Buildpacks automatically detect your application language and create an optimized container image without writing a Dockerfile. They handle dependency installation, compilation, and runtime configuration based on conventions for each language.

Quick Start

Build and push an image using buildpacks:
cpln image build --name my-app:v1 --push
If your project has no Dockerfile, the CLI will install pack (if not already available) and use pack build under the hood. All buildpack-related flags are passed directly to pack.

Build Options

FlagDescription
--builder, -BCNB-compatible builder image (default: heroku/builder:24)
--buildpack, -bAdditional buildpack to use (can be specified multiple times)
--dirBuild context directory (default: current directory)
--pushPush the image to your org’s private registry after building
--no-cacheBuild without using cache
--env, -eEnvironment variable for the build (can be specified multiple times)
--env-fileFile containing environment variables (can be specified multiple times)
--trust-builderTrust the builder image (skip security prompts)
--trust-extra-buildpacksTrust additional buildpacks
--platform, -pTarget platform (default: linux/amd64)

Common Builders

BuilderDescription
heroku/builder:24Default. Supports Node.js, Python, Go, Java, Ruby, PHP, and more
gcr.io/buildpacks/builder:google-22Google Cloud buildpacks
paketobuildpacks/builder-jammy-basePaketo community buildpacks (includes .NET, Rust support)

Language Conventions

The following conventions apply to the default heroku/builder:24 unless otherwise noted. Other builders may have different requirements.
Required files:
  • package.json in the project root
  • package-lock.json in the project root
Run npm install before building to ensure package-lock.json is up to date with your dependencies.
Start command:
  • If index.js or server.js exists in the root, it will be used automatically
  • Otherwise, add a scripts.start command in package.json
  • Alternatively, create a Procfile in the project root
Example Procfile:
web: node src/app.js
Example package.json (with start script):
{
  "name": "my-app",
  "scripts": {
    "start": "node src/app.js"
  },
  "engines": {
    "node": "20.x"
  }
}
Example package.json (with index.js or server.js in root):
{
  "name": "my-app",
  "engines": {
    "node": "20.x"
  }
}
Specify your Node.js version in engines.node to ensure consistent builds.
Detection (required - one of):
  • requirements.txt (pip)
  • uv.lock (uv)
  • poetry.lock (Poetry)
These files are used to detect a Python app and install dependencies.Extra requirements:
  • Using uv requires a .python-version file
  • Using Poetry for a non-packaged app requires package-mode = false in pyproject.toml
Start command (required for web apps):
  • Create a Procfile in the project root
  • Python buildpacks do not auto-detect an entry file
  • Without a Procfile, the app may build but will not start
Example Procfile:
web: gunicorn -b 0.0.0.0:$PORT app:app
Runtime requirements:
  • Server must bind to 0.0.0.0
  • Server must listen on $PORT
Example requirements.txt:
flask==3.0.0
gunicorn==21.2.0
Required files:
  • go.mod in the project root
Project structure:
  • The main package must be in the project root
Build behavior:
  • Compiles the main package
  • Binary is automatically set as the start command
Example go.mod:
module github.com/myorg/myapp

go 1.21
Required files:
  • pom.xml in the project root
Build behavior:
  • Runs mvn package
Start command:
  • Spring Boot JARs: start command is auto-detected
  • Non-Spring executable JARs: add a Procfile (recommended)
Runtime requirements:
  • Server must bind to 0.0.0.0
  • Server must listen on $PORT
If you need a specific JDK version, pin it explicitly (otherwise the builder default may be used).
Example pom.xml excerpt (Spring Boot):
<packaging>jar</packaging>
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>
Required files:
  • build.gradle or build.gradle.kts in the project root
  • gradlew (Gradle Wrapper) in the project root
Build behavior:
  • Runs ./gradlew build
Start command:
  • Spring Boot JARs: start command is auto-detected
  • Non-Spring executable JARs: add a Procfile (recommended)
Runtime requirements:
  • Server must bind to 0.0.0.0
  • Server must listen on $PORT
If you need a specific Java version, add system.properties (e.g. java.runtime.version=21). Avoid Gradle toolchains unless you configure toolchain downloads.
Required files:
  • Gemfile and Gemfile.lock in the project root
Start command:
  • Rails apps: default start command exists, but a Procfile is recommended
  • Non-Rails apps: create a Procfile with web: <command>
Runtime requirements:
  • Server must listen on $PORT
Example Procfile (non-Rails):
web: bundle exec puma -p $PORT config.ru
Example Procfile (Rails with Puma):
web: bundle exec puma -C config/puma.rb
Required files:
  • composer.json and composer.lock in the project root
Start command:
  • Create a Procfile with web: <command>
Example Procfile (Apache):
web: heroku-php-apache2 public/
Rust is not supported by the default heroku/builder:24. Use the Paketo Community Rust buildpack.Required files:
  • Cargo.toml in the project root
  • Cargo.lock in the project root
  • A binary target (e.g. src/main.rs or src/bin/*.rs)
Build command:
cpln image build --name my-rust-app:v1 --push -b docker.io/paketocommunity/rust
Build behavior:
  • Builds the project using cargo build --release
  • The resulting binary is used as the default launch command (or can be overridden via a Procfile)
Example Cargo.toml:
[package]
name = "my-app"
version = "0.1.0"
edition = "2021"

[dependencies]
actix-web = "4"
Process configuration (optional):
web: my-app
Note: The binary name is derived from [package].name and must match the Procfile entry exactly.
Runtime requirements:
  • Server must listen on $PORT (read from environment variable)
C# / .NET is not supported by the default heroku/builder:24. Use the Paketo .NET buildpacks via a Paketo builder.Required files:
  • A .csproj or .fsproj file in the project root, or
  • A .sln file with referenced projects
Build command:
cpln image build --name my-dotnet-app:v1 --push -B paketobuildpacks/builder-jammy-base
Build behavior:
  • Runs dotnet publish (Release)
  • Automatically detects the entry point DLL for single-project apps
Start command:
  • Auto-detected for single-project solutions
  • Optional: add a Procfile to explicitly set or override the start command (recommended for multi-project solutions)
Example .csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
  </PropertyGroup>
</Project>
Example Procfile (optional):
web: dotnet MyApp.dll
Runtime requirements:
  • Server must bind to 0.0.0.0 (not 127.0.0.1)
  • Server must listen on $PORT (recommended: set ASPNETCORE_URLS to http://0.0.0.0:$PORT)
The simplest way to ensure correct port binding is to set ASPNETCORE_URLS in your workload:
ASPNETCORE_URLS=http://0.0.0.0:$PORT

The Procfile

A Procfile defines how your application is started by the platform. Place it in the project root.
web: <start-command>
Notes:
  • Some languages auto-detect a start command (e.g., Go binaries, Spring Boot JARs)
  • Other languages require a Procfile to start a web server

Build Examples

# Basic build with auto-detection
cpln image build --name my-app:v1 --push

# Use a different builder
cpln image build --name my-app:v1 --push -B gcr.io/buildpacks/builder:google-22

# Add a specific buildpack (e.g., for Rust)
cpln image build --name my-rust-app:v1 --push -b docker.io/paketocommunity/rust

# Pass build-time environment variables
cpln image build --name my-app:v1 --push -e NODE_ENV=production -e LOG_LEVEL=info

# Use an env file
cpln image build --name my-app:v1 --push --env-file .env.build

# Build for a different platform
cpln image build --name my-app:v1 --push --platform linux/arm64

# Trust builder and extra buildpacks (useful in CI/CD)
cpln image build --name my-app:v1 --push --trust-builder --trust-extra-buildpacks

Troubleshooting

The buildpack built your image but doesn’t know how to start it. Common causes:
  1. Missing Procfile: Create a Procfile in your project root:
    web: <your-start-command>
    
  2. Missing start script (Node.js): Add a start script to package.json:
    "scripts": {
      "start": "node server.js"
    }
    
  3. Wrong port: Your app must listen on the $PORT environment variable, not a hardcoded port.
Buildpacks detect languages based on specific files. Ensure you have the required files for your language:
LanguageRequired File(s)
Node.jspackage.json + package-lock.json
Pythonrequirements.txt, uv.lock, or poetry.lock
Gogo.mod
Javapom.xml or build.gradle
RubyGemfile + Gemfile.lock
PHPcomposer.json + composer.lock
RustCargo.toml + Cargo.lock (requires -b docker.io/paketocommunity/rust)
C# / .NET.csproj, .fsproj, or .sln (requires -B paketobuildpacks/builder-jammy-base)
Rust and C# / .NET are not supported by the default heroku/builder:24. You must specify an additional buildpack or use a different builder as shown above.
In CI/CD environments, add the trust flags:
cpln image build --name my-app:v1 --push --trust-builder --trust-extra-buildpacks
These languages require different builders or buildpacks:Rust:
cpln image build --name my-app:v1 --push -b docker.io/paketocommunity/rust
C# / .NET:
cpln image build --name my-app:v1 --push -B paketobuildpacks/builder-jammy-base
Buildpacks cache dependencies between builds. If builds are slow:
  1. Ensure you’re not using --no-cache unless necessary
  2. Check if your dependency files changed (triggers full rebuild)
  3. Consider using a builder optimized for your language

Learn More