heroku/deb-packages is a Heroku Cloud Native Buildpack that adds support for installing Debian
packages required by an application that are not available in the build or run image used.
System dependencies on Debian distributions like Ubuntu are described by <package-name>.deb files. These are
typically installed using CLI tools such as apt or dpkg. This buildpack implements logic to install packages
from .deb files in a CNB-friendly manner that does not require root permissions or modifications to system files
that could invalidate how CNB rebasing functionality works.
Important
This is a Cloud Native Buildpack, and is a component of the Heroku Cloud Native Buildpacks project. If you are instead looking for the Heroku Classic Apt Buildpack you may find it here.
This buildpack is compatible with the following environments:
| OS | Arch | Distro Name | Distro Version |
|---|---|---|---|
| linux | amd64 | Ubuntu | 24.04 |
| linux | arm64 | Ubuntu | 24.04 |
| linux | amd64 | Ubuntu | 22.04 |
Note
Before getting started, ensure you have the pack CLI installed. Installation instructions are available here.
To include this buildpack in your application:
pack build my-app --builder heroku/builder:24 --buildpack heroku/deb-packagesAnd then run the image:
docker run --rm -it my-appThe configuration for this buildpack must be added to the project descriptor file (project.toml) at the root of your
project using the com.heroku.buildpacks.deb-packages table. The list of packages to install must be
specified there. See below for the configuration schema and an example.
# _.schema-version is required for the project descriptor
[_]
schema-version = "0.2"
# buildpack configuration goes here
[com.heroku.buildpacks.deb-packages]
# one or more packages from Debian repositories can be provided with the following:
install = [
# string version of a dependency to install
"package-name",
# inline-table version of a dependency to install
{ name = "package-name", skip_dependencies = true, force = true }
]
# one or more custom urls for Debian packages can be provided with the following:
download = ["https://example.com/package-1.2.3.deb"]
# one or more custom sources can be configured with the following:
[[com.heroku.buildpacks.deb-packages.sources]]
uri = "<url_of_debian_repository> (e.g.; http://archive.ubuntu.com/ubuntu)"
suites = ["<suite> (e.g.; jammy)"]
components = ["<component> (e.g.; main)"]
arch = ["<architecture> (e.g.; amd64 or arm64)"]
signed_by = """-----BEGIN PGP PUBLIC KEY BLOCK-----
<ASCII-armored GPG key>
-----END PGP PUBLIC KEY BLOCK-----
"""-
com.heroku.buildpacks.deb-packages(table, optional)The root configuration for this buildpack.
-
install(array, optional)A list of one or more packages to install. Each package can be specified in either of the following formats:
-
(string)
The name of the package to install.
OR
- (inline-table)
-
name(string, required)The name of the package to install.
-
skip_dependencies(boolean, optional, default = false)If set to
true, no attempt will be made to install any dependencies of the given package. -
force(boolean, optional, default = false)If set to
true, the package will be installed even if it's already installed on the system.
-
-
-
download(array, optional)A list of one or more packages to install. Each package can be specified in either of the following formats:
-
(string)
The url to download the package from.
-
-
sources(array_of_tables, optional)-
uri(string, required)The URI must specify the base of the Debian repository.
-
suites(array of string values, required)One or more distribution suites from the Debian repository.
-
components(array of string values, required)One or more components which specify different sections of distribution versions present in a suite.
-
arch(array of string values, required)One or more supported architecture names. The supported architecture names are:
- amd64
- arm64
-
signed_by(string, required)The GPG key required by the Debian repository in ASCII-armored format.
-
-
Tip
Users of the heroku-community/apt can migrate their Aptfile to the above configuration by
adding a project.toml file with:
[_]
schema-version = "0.2"
[com.heroku.buildpacks.deb-packages]
# packages to install are listed here:
install = ["libexample-dev"]
# links to specific .deb files are listed here:
download = ["https://downloads.example.com/example.deb"]
# custom apt repos like ":repo:deb https://apt.example.com/ example-distro main" become:
[[com.heroku.buildpacks.deb-packages.sources]]
uri = "https://apt.example.com/"
suites = ["example-distro"]
components = ["main"]
arch = ["<architecture> (e.g.; amd64 or arm64)"]
signed_by = """-----BEGIN PGP PUBLIC KEY BLOCK-----
<ASCII-armored GPG key>
-----END PGP PUBLIC KEY BLOCK-----
If your Aptfile contains a package name that uses wildcards (e.g.; mysql-*) this must be replaced with the full list
of matching package names.
The following environment variables can be passed to the buildpack:
| Name | Value | Default | Description |
|---|---|---|---|
BP_LOG_LEVEL |
INFO,DEBUG |
INFO |
Configures the verbosity of buildpack output. The DEBUG level is a superset of the INFO level. |
This buildpack will pass detection if:
- A
project.tomlfile is found at the root of the application source directory containing configuration under the[com.heroku.buildpacks.deb-packages]namespace. - An
Aptfileis found. This will not be used by this buildpack but details for how to migrate away fromAptfileconfiguration will be provided in the build phase if this file is present.
Each supported distro is configured to download from the following Ubuntu repositories:
main- Canonical-supported free and open-source software.universe- Community-maintained free and open-source software.
These repositories comply with the Debian Repository Format so building the list of packages involves:
- Downloading the Release file, validating its
OpenPGP signature, and caching this in a layer available at
build. - Finding and downloading the Package Index entry from the Release for the target
architecture and caching this in a layer available at
build. - Building an index of Package Name → (Repository URI, Binary Package) entries that can be used to lookup information about any packages requested for install.
For each package requested for install declared in the buildpack configuration:
- Lookup the Binary Package in the Package Index.
- Check if the requested package is already installed on the system
- If it is already installed and the requested package is configured with
force = false- Skip the package
- If it is already installed and the requested package is configured with
- If the requested package is configured with
skip_dependencies = false:- Add the latest version of the requested package.
- Read the dependencies listed in the Depends and Pre-Depends from the Binary Package.
- For each dependency:
- Recursively lookup the dependent package and follow the same steps outlined above until all transitive dependencies are added.
- If the requested package is configured with
skip_dependencies = true:- Add the latest version of the requested package.
Note
This buildpack is not meant to be a replacement for a fully-featured dependency manager like Apt. The simplistic dependency resolution strategy described above is for convenience, not accuracy. Any extra dependencies added are reported to the user during the build process so, if they aren't correct, you should disable the dependency resolution on a per-package basis with configuration and explicitly list out each package you need installed.
For each package added after determining the packages to install:
- Download the Binary Package from the repository that contains it as a Debian Archive.
- Extract the contents of the
data.tarentry from the Debian Archive into a layer available atbuildandlaunch. - Rewrite any pkg-config files to use a
prefixset to the layer directory of the installed package. - Configure the following layer environment variables to be available at both
buildandlaunch:
| Environment Variable | Appended Values | Contents |
|---|---|---|
PATH |
/<layer_dir>/bin /<layer_dir>/usr/bin /<layer_dir>/usr/sbin /<layer_dir>/usr/local/bin /<layer_dir>/usr/local/sbin |
binaries |
LD_LIBRARY_PATH |
/<layer_dir>/usr/local/lib/<arch> /<layer_dir>/usr/lib/<arch> /<layer_dir>/usr/lib /<layer_dir>/lib/<arch> /<layer_dir>/lib |
shared libraries |
LIBRARY_PATH |
Same as LD_LIBRARY_PATH |
static libraries |
INCLUDE_PATH |
/<layer_dir>/usr/local/include/<arch> /<layer_dir>/usr/include/<arch> /<layer_dir>/usr/include |
header files |
CPATH |
Same as INCLUDE_PATH |
header files |
CPPPATH |
Same as INCLUDE_PATH |
header files |
PKG_CONFIG_PATH |
/<layer_dir>/usr/local/lib/<arch>/pkgconfig /<layer_dir>/usr/lib/<arch>/pkgconfig /<layer_dir>/usr/lib/pkgconfig |
pc files |
Issues and pull requests are welcome. See our contributing guidelines if you would like to help.