Managing Buildpacks
Last updated December 04, 2024
Table of Contents
- When to Add or Customize Buildpacks
- Set a Buildpack on an App
- Set a Classic Buildpack
- Set a Cloud Native Buildpack
- View Your Buildpacks
- Remove a Buildpack
- Use Multiple Buildpacks
- Using Third-Party Buildpacks
- Change a CNB App’s Base Image or Builder
- Set CNB Build Environment Variables
- Buildpack References
- Migrate an App Between Using Classic Buildpacks to CNBs
- Additional Reading
For many apps that use one of Heroku’s supported languages, we automatically detect the appropriate buildpack to use for it. The buildpack installs required binaries, downloads required dependencies, compiles source code, and more. In these cases, it’s not necessary to customize the buildpacks used for a build.
This article covers when and how you can manage and customize your app’s buildpacks. There are different experiences for managing classic buildpacks and Cloud Native Buildpacks.
When to Add or Customize Buildpacks
There are many reasons why you need to manually add buildpacks, like if your app:
- requires a binary that isn’t included in the Heroku base image by default, such as
ffmpeg
. - uses a language not directly supported by Heroku, such as Rust.
- requires a custom build tool that isn’t provided by Heroku’s buildpacks, such as
nx
ortask
. - requires multiple buildpacks for asset handling using a Node.js library in combination with a Ruby, Python or PHP application.
While we usually detect the correct buildpack to use, failures can occur. In these cases, you can also manually set the buildpack.
Set a Buildpack on an App
You can set official Heroku buildpacks or third-party buildpacks on your app. There are different experiences for setting classic buildpacks and CNBs.
Set a Classic Buildpack
Change the classic buildpack used by an app in Cedar by setting the buildpack value.
You can refer to a classic buildpack in many ways. The following examples use the recommended short-form Buildpack Registry name, which always points to the buildpack’s latest release version.
On App Creation
To specify a buildpack during app creation:
$ heroku create example-app --buildpack heroku/python
For Existing Apps
For existing apps, use heroku buildpacks:set
:
$ heroku buildpacks:set heroku/php --app example-app
Buildpack set. Next release on example-app will use heroku/php.
Run `git push heroku main` to create a new release using this buildpack.
Add Multiple Buildpacks
Add additional buildpacks to your application with the buildpacks:add
command.
For example, if you have an app with a Scala buildpack, and need to add the Node.js buildpack:
$ heroku buildpacks:add --index 1 heroku/nodejs --app example-app
This command inserts the Node.js buildpack at the first position in the order of buildpack execution, and moves the other buildpacks ahead of it down one position. The Scala buildpack that was already set is now the second buildpack to run.
Here’s an example of a specific use case for this command: Using Node.js to Perform JavaScript Optimization for Play and Scala Applications.
Always put the buildpack for the primary language of your app as the last buildpack in the list. This ordering ensures that defaults for that primary language get applied instead of those for another language. It also allows Heroku to correctly detect the primary language of your app.
You can also insert a single buildpack with the heroku buildpacks:set
command with the optional --index
argument to set the position of it in the order of execution. If --index
is provided, the command overwrites the buildpack at the given position.
With app.json
You can set a classic buildpack explicitly in app.json
so that applications created by Heroku Buttons, Heroku CI or Review Apps. See app.json
Schema for more info.
Changing app.json
doesn’t update the settings of existing apps. You must set them on existing apps with the heroku buildpacks
command instead.
Set a Cloud Native Buildpack
You can choose the Cloud Native Buildpacks for your build by setting them in project.toml in the root directory of your app repo. You can add one or multiple buildpacks to the file, which get executed in a specific order. See the CNB specification for more details.
For example, if you need both Node.js and Go in the same CNB build, include these contents in project.toml:
[_]
schema-version = "0.2"
[[io.buildpacks.group]]
id = "heroku/nodejs"
[[io.buildpacks.group]]
id = "heroku/go"
Then commit the file to git, and push to Heroku:
$ git add project.toml
$ git commit -m "Set custom CNB"
$ git push heroku main
Note that the app must still pass detection for the buildpacks specified. For example, if heroku/ruby is specified, a Gemfile must still be present or the build fails.
Custom buildpacks included in the app source code, for example, “relative buildpacks”, are unsupported.Use inline buildpacks instead.
Inline Buildpacks
To run a script specifically for an app, you can inline a buildpack directly into the project.toml by giving it an id and a script:
[[io.buildpacks.group]]
id = "my-inline-buildpack"
[io.buildpacks.group.script]
api = "0.10"
inline = "echo 'Hello World'"
Add multi-line scripts by using TOML “”“ heredoc delimiters:
[[io.buildpacks.group]]
id = "my-inline-buildpack"
[io.buildpacks.group.script]
api = "0.10"
inline = """
echo 'Hello World'
echo 'Goodbye'
"""
project.toml Requirements & Limitations
The project.toml project descriptor is part of the CNB framework. Heroku Fir supports most, but not all types of configurations that can be included.
- Schema version must be 0.2 or omitted.
- Platform API version must be 0.12.
- Builder must be from the
heroku/builder
repository. Heroku currently only supports the Heroku-24 builder,heroku/builder:24
. include
andexclude
are unsupported.- Relative custom buildpacks are unsupported.
View Your Buildpacks
You can view the complete list of buildpacks for an app by running this command:
$ heroku buildpacks
=== nameless-brushlands-4859 Buildpack
1. heroku/nodejs
2. heroku/ruby
The last buildpack in the listed gets used to determine the process types for the application. Any process types defined from earlier buildpacks get ignored.
You can run heroku help buildpacks
to get a full list of options for the command.
Remove a Buildpack
Remove Classic Buildpacks
You can remove a buildpack from an app:
$ heroku buildpacks:remove heroku/nodejs
When no buildpack is set on your application, the detection process will be run again on your next git push heroku
.
To clear all buildpacks from the app:
$ heroku buildpacks:clear --app example-app
Remove Cloud Native Buildpacks
Remove the buildpack from project.toml, commit your code and push to Heroku.
Use Multiple Buildpacks
There are many scenarios in which a single buildpack is not sufficient when building an application. This includes cases when you need to:
- run a buildpack for each language your app uses. For example, run a JavaScript buildpack for assets and a Ruby buildpack for your application.
- run a daemon process with your application.
- pull in system dependencies with
apt
.
You can define the specific buildpacks your app needs and their order of execution. See the instructions for setting buildpacks for more info.
Using Third-Party Buildpacks
Find Buildpacks
See Officially Supported Buildpacks to see a list of Heroku’s classic buildpacks and CNBs.
You can use custom third-party buildpacks to support languages or frameworks not covered by Heroku’s officially supported buildpacks.
Custom Classic Buildpacks
Third-party buildpacks contain software that’s not under Heroku’s control, and are unsupported by Heroku. Inspect the source of any buildpack you plan to use and proceed with caution.
For a curated list of custom, third-party classic buildpacks, check out the Elements marketplace.
You can also search through hundreds of custom buildpacks via the CLI. To search, run:
$ heroku buildpacks:search elixir
Buildpack Category Description
─────────────── ───────── ───────────────────────────
hashnuke/elixir languages Heroku Buildpack for Elixir
$ heroku buildpacks:info hashnuke/elixir
description: Heroku Buildpack for Elixir
category: languages
license: MIT License
support: https://github.com/HashNuke/heroku-buildpack-elixir/issues
source: https://github.com/HashNuke/heroku-buildpack-elixir
readme:
You can add custom buildpacks using the same commands as official classic buildpacks by using the buildpack’s namespace/name or Git URL.
Custom Cloud Native Buildpacks
Third-party buildpacks contain software that’s not under Heroku’s control, and are unsupported by Heroku. Inspect the source of any buildpack you plan to use and proceed with caution.
Both officially supported Heroku CNBs and third-party CNBs are in the Cloud Native Buildpacks Registry at https://registry.buildpacks.io. Heroku’s officially supported buildpacks are listed in the registry under the heroku
scope, for example heroku/go
. Many third-party CNBs listed in the registry work with Heroku’s CNB Builders and Heroku Fir, but are not officially supported by Heroku. You can add them like other CNBs in your project.toml
.
Change a CNB App’s Base Image or Builder
You can’t change a CNB’s base image directly as it’s part of the builder. By default, CNB builds on the Heroku Fir platform use the heroku/builder:24 CNB builder, which uses Heroku-24 base images. On Heroku, you can only use a builder from the heroku/builder repository. Heroku currently only supports the heroku-24
builder.
You must set the version of Heroku’s base image for apps using classic buildpacks with heroku stacks:set
.
Set CNB Build Environment Variables
An app’s config vars are unavailable during builds, but you can set environment variables for use during the build. Keep in mind that since these environment variables are in project.toml
, they get committed to the repository. Never set sensitive data or secrets via project.toml
.
[_]
schema-version = "0.2"
[[io.buildpacks.build.env]]
name = "NODE_ENV"
value = "production"
Buildpack References
Classic Buildpacks References
Heroku only provides support for official buildpacks if you use the latest stable release via the heroku/…
shorthand name.
Using an official buildpack’s GitHub URL can result in degraded performance or undocumented behavior.
You can set buildpack values with any of the following:
- the short-form Buildpack Registry name (for published buildpacks), for example,
heroku/python
- the URL of a Git repository, for example,
https://github.com/heroku/heroku-buildpack-nodejs.git
- a gzipped tarball URL
When the source of the buildpack you use is a Git repository, you can specify a specific tag or branch of that buildpack to use by appending a Git object, such as a tag name, branch name, or 40-character commit SHA to the URL. For example:
https://github.com/heroku/heroku-buildpack-nodejs.git#somedevbranch
https://github.com/heroku/heroku-buildpack-nodejs.git#v9861
https://github.com/heroku/heroku-buildpack-nodejs.git#a2113e0671bc132310ff9f85ad07f5a19f217313
Never set a branch name or commit reference using the ….git#ref
notation unless explicitly instructed to do so by Heroku Support as a temporary measure,
This action can result in your application not using up-to-date and secure dependencies, builds failing, or undefined behavior at runtime.
Cloud Native Buildpacks References
See the official Buildpacks.io docs for all the methods you can reference CNBs.
Migrate an App Between Using Classic Buildpacks to CNBs
You can’t migrate apps between using classic buildpacks and CNBs.
You must redeploy your Cedar-generation app to Fir, which then automatically uses CNBs instead of classic buildpacks.
You must redeploy your Fir-generation app to Cedar, which then automatically uses classic buildpacks instead of CNBs.