Heroku Go Support
Last updated December 04, 2024
Table of Contents
This document describes the general behavior of Heroku as it relates to the recognition and execution of Go applications. For a more detailed explanation of how to deploy an application, see Getting Started with Go on Heroku.
Supported Dependency/Vendor Managers
Go Modules is the only non-deprecated dependency/vendor manager we support.
Deprecated Dependency/Vendor Managers
For Cedar-generation apps, support is deprecated for the following dependency/vendor managers:
Auto-Detection
The Heroku Go buildpack is used when an application has a go.mod
file, identifying the application as being managed by Go Modules
For Cedar-generation apps, which use classic buildpacks, besides a go.mod
file, the Go buildpack can also be used if your application has one of the following:
- a
Godeps/Godeps.json
file, identifying the application as being managed by godep - a
vendor/vendor.json
file, identifying the application as being managed by govendor - a
src
directory, which has sub directories, contains one or more.go
files, identifying the application as being managed by gb
When a deployed application is recognized as a Go application, Heroku responds with -----> Go app detected
, like so:
$ git push heroku main
...
remote: -----> Go app detected
...
We do basic structural validation of the various metadata files (go.mod
, Godeps.json`, etc) before attempting to use them. If there is an error, it displays like so:
$ git push heroku main
...
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Go app detected
remote: -----> Checking Godeps/Godeps.json file.
remote: parse error: Expected value before ',' at line 4, column 15
remote: ! Bad Godeps/Godeps.json file
remote:
remote: ! Push rejected, failed to compile Go app
...
Go Versions
Heroku makes a number of different versions of the Go toolchain available. The currently supported versions listed here. Any version is available for use, but support is generally only provided for the latest current minor release of the last 2 major versions.
The major release identifier is used to represent the latest release in that series. Example: go1.22
expands to the latest go 1.2 release that Heroku supports at the time the code was built, go1.22.4
, go1.22.5
, go1.22.6
, etc.
To select a specific minor revision (e.x. go1.21.8
), you must manually edit the appropriate metadata file or set the $GOVERSION
environment variable, depending on the dependency manager you use:
- Go Modules
- godep
- govendor
- gb
- dep (community supported*)
In the rare case that you need to pin to the first release of a major version add a .0
to the version identifier. Example: go1.23.0
pins an app’s go version to go1.23
.
Passing a symbol (and optional string) to the linker
Heroku supports the Go linker’s ability (-X symbol value) to set the value of a string at link time. This can be done by setting $GO_LINKER_SYMBOL
and $GO_LINKER_VALUE
in the application’s config before pushing code. If $GO_LINKER_SYMBOL
is set, but $GO_LINKER_VALUE
isn’t set then $GO_LINKER_VALUE
defaults to $SOURCE_VERSION
.
This can be used to embed the commit SHA, or other build specific data directly into the compiled executable.
Other Build Time Behavior
Various aspects of the build can be controlled via several application config vars. Below is a list of the vars that are not covered elsewhere in this doc and what they control:
CGO_CFLAGS
,CGO_CPPFLAGS
,CGO_CXXFLAGS
andCGO_LDFLAGS
: These are the standard CGO flags as described here.GOPROXY
,GOPRIVATE
, andGONOPROXY
: These and the standard environment variables that configure use of module proxies as described here.GOVERSION
: Provides an override to the go version to use.GO_INSTALL_PACKAGE_SPEC
: Overrides the package spec passed togo install
with this value. This is useful when you have a large repo, but only want to compile a sub section of it.GO_INSTALL_TOOLS_IN_IMAGE
: When set totrue
, installs the go tool chain into the slug at$HOME/.heroku/go
, set’s$GOROOT=$HOME/.heroku/go
and includes$GOROOT/bin
in your$PATH
. Normally the go tools are not installed in the slug. This increases the slug size by about 81MB.GO_SETUP_GOPATH_IN_IMAGE
: When set totrue
$GOPATH=$HOME
is set and user code is placed in the appropriate location inside of the$GOPATH
(e.g.$GOPATH/src/github.com/heroku/go-getting-started
). When the dyno starts the working directory gets set to root of the user code. Normally the buildpack keeps user code in$HOME
. This is most useful when used in conjunction withGO_INSTALL_TOOLS_IN_IMAGE=true
so that there is a fully functioning go workspace and tool chain inside of the dyno.
Each of the above config vars need to be set on an application before pushing code and code must be pushed after these config vars are set for them to take effect.
Runtime Behavior
Starting with go1.5 and newer, the buildpack does not set any Go runtime environment variables. You can set these environment variables on your application’s config and the application is restarted with them in place. For go1.4 and older a default $GOMAXPROCS
is set, depending on the size of your dyno. This can be overridden by using heroku config:set
to set a value for GOMAXPROCS
.
The runtime environment does not have a copy of the go tool chain or the compiled package files (*.a
) as the build pack does not copy them into the slug.
Static Assets & Files
Anything included in your git repository is available at runtime and can be served from the local filesystem using Go’s http.FileServer
or framework equivalent. Tools like go-assets, go-bindata & statik are not required.
Default Process Types
Heroku adds default process types if and only if all of the following conditions are met:
- The application uses Go modules
- The application does not already have a Procfile
- One or more Go packages were detected in the project
If Heroku detects one Go package, Heroku adds that package as a process type with the name web
. If Heroku detects multiple Go packages, Heroku adds a process type for each package using the name of the package.
To select or override the process types for your application, use a Procfile. See one of the Go tutorials for information on setting up your Procfile.
Add-ons
No add-ons are provisioned by default. To add a SQL database for your app:
$ heroku addons:create heroku-postgresql --app example-app
Vendor Directory Support
Builds use the contents of the vendor/
directory when compiling as if they are in your $GOPATH
. If you choose to vendor, be careful when specifying the package path(s); ./...
matches all packages, which may include those in vendor/
. Heroku suggests putting individual main packages for executables inside of subdirectories of the cmd
directory like detailed in this blog post.
Vendoring Additional Main Packages
Various vendoring tools can save additional packages beyond those in your local project into your project’s vendor directory. This is useful when you want to include, compile and install additional main packages. A common usage is to include a package like migrate to manage database migrations.
Go Modules
To install dependencies that aren’t imported into your application’s Go source code, you’ll need to add a Heroku build directive to your go.mod
. Learn more about go.mod
Heroku build directives here. For example:
// +heroku install ./cmd/... github.com/golang-migrate/migrate
Godep
godep
support is deprecated, and Cedar-generation only.
To have godep save additional packages, those packages must be installed in your $GOPATH and included on the command line every time godep save
is run like so: godep save ./cmd/... github.com/golang-migrate/migrate
. The resulting changes to Godeps/Godeps.json
and either vendor/
or Godeps/_workspace
need to be committed.
On the next push, Heroku installs both ./cmd/...
and github.com/golang-migrate/migrate
.
govendor
govendor
support is deprecated, and Cedar-generation only.
govendor can fetch and save additional packages beyond those in your local project directly into your vendor/
directory like so: govendor fetch github.com/golang-migrate/migrate
.
Additionally, the heroku build configuration section of vendor.json
needs to have the additional packages added to the heroku.install
array like so:
...
"heroku" : {
...
"install": [
"./cmd/...",
"github.com/golang-migrate/migrate"
]
},
...
The changes to vendor/*
need to be committed. On the next push, Heroku installs both ./cmd/...
and github.com/golang-migrate/migrate
.
Going Further
The Heroku Go buildpacks are open source. For a better technical understanding of how these buildpacks work, check out the source code.
- The Cedar-generation Classic Buildpack for Go is here: github.com/heroku/heroku-buildpack-go
- The Fir-generation Cloud Native Buildpack for Go is here: github.com/heroku/buildpacks-go