Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Selecting Runtime Versions

The framework selects a builder. Your repository selects the language version. The version catalog lists installable versions separately from upstream maintenance status and d2o verification, for production and staging. An upstream release is not necessarily available in the deployed builder yet.

Put version files at the app root: the repository root, or the selected source directory for a shared repository. Commit them together with dependency lockfiles. Exact pins improve repeatability; ranges let later builds select newer matching releases. A removed or incompatible version fails the build.

Node.js

Set engines.node in package.json:

{
  "engines": { "node": "24.x" },
  "scripts": { "start": "node server.js" }
}

24.x selects an available patch in that major line. An exact version, such as 24.0.0, requests that release; check its availability and support status before using it. Without a requirement, the Heroku Node.js buildpack selects its default LTS line. Defaults belong to the deployed buildpack and may change on an update. Commit the package manager’s lockfile too.

Static frontend compilation uses Paketo’s Node engine, with its own inventory and defaults. It accepts BP_NODE_VERSION, then package.json engines, .nvmrc, and .node-version, in that order. Do not assume its versions match the Node.js application builder. See the static site guide.

Ruby and Rails

Use the rails framework for Ruby applications, including non-Rails applications. Declare Ruby in your Gemfile and update the lockfile:

source "https://rubygems.org"
ruby "3.3.9"
bundle update --ruby
git add Gemfile Gemfile.lock

The buildpack installs the version resolved in Gemfile.lock’s RUBY VERSION section. Changing only the Gemfile does not update that recorded version. An omitted lockfile version uses the buildpack default. A .ruby-version file can supply the Gemfile declaration via Bundler’s ruby file: ".ruby-version"; commit the updated lockfile as well. The catalog shows which exact releases can be downloaded for d2o’s stack.

Python

Commit .python-version:

3.14

A minor version uses the latest patch mapped by the deployed buildpack. An exact patch requests that artifact, provided the buildpack accepts the minor line and the artifact remains downloadable. Older downloadable patches are not necessarily maintained or verified. Without this file, the buildpack normally selects its default; projects using uv may require the file explicitly. Use the existing dependency manager’s lockfile and a Procfile for the web/worker command. Bind a web server to 0.0.0.0 and the injected PORT.

Go

The Heroku Go builder reads go.mod:

module example.com/service

go 1.26

A two-component directive selects an available patch in that minor line. A three-component directive selects that exact version in this buildpack. For an explicit buildpack requirement, use its supported comment:

// +heroku goVersion =1.26.0

That comment takes precedence over go. The deployed buildpack’s parser does not use the toolchain directive to select its initial compiler. The Go command can independently select/download another toolchain under Go’s GOTOOLCHAIN rules, so keep declarations consistent and check the build log. When no version is requested, the buildpack selects from its inventory. See deploying Go.

Rust

Commit Cargo.toml, Cargo.lock, and optionally rust-toolchain.toml:

[toolchain]
channel = "1.90.0"
profile = "minimal"

The version above illustrates an exact pin; use the catalog to choose a maintained release. The Paketo community Rust builder uses rustup and defaults to stable. The toolchain file can select an exact stable release, stable, beta, nightly, or a dated nightly such as nightly-2026-09-01. Channel names move over time; an exact or dated toolchain must still be available for the builder’s target. Beta and nightly are experimental, and d2o does not test every historical nightly.

package.rust-version in Cargo.toml declares the minimum supported Rust version for your package; it does not pin the compiler. For multiple binaries, select the generated process type in the app’s Process setting.

Updates and rebuilds

Runtime versions, buildpack versions, and operating-system stacks are separate. kpack can rebuild an unchanged application commit when a buildpack or stack changes. Such a rebuild can select a newer matching runtime when your requirement is a range or a channel. Pinning a runtime does not freeze the builder or OS.

A failed image build never becomes a running version. A built version must then pass its deployment health checks. Automatic rollback restores the previous image, not database or object-storage contents.

The catalog is refreshed daily and after builder promotions. Its tested status applies to a small build-and-HTTP fixture on the recorded builder digest, not to every dependency an application could use. Historical Rust releases and end-of-life language versions may remain downloadable without being supported.

Upstream references