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.