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

Images Reference

Conceptual overview of images in Control Plane

Push Images Guide

Detailed guide for building and pushing images

CLI Image Commands

Full CLI command reference

Buildpacks.io

Official Cloud Native Buildpacks documentation