Deploying Go on Vessl
Vessl detects Go automatically via go.mod and builds your app with Nixpacks. This guide covers HTTP servers, binary builds, and database connections.
Prerequisites
- A server added and provisioned in Vessl
- A GitHub repository with your Go app
go.modat the repository root (or in your Root Directory for monorepos)
What Vessl auto-detects
When Vessl finds go.mod it sets:
| Setting | Auto-filled value |
|---|---|
| Build engine | Nixpacks |
| Port | 8080 |
Nixpacks compiles your Go binary and sets the start command automatically. It runs go build on the package at the module root and starts the resulting binary.
Step 1 — Make sure your app listens on PORT
Vessl injects a PORT environment variable. Read it in your server setup:
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/", handler)
fmt.Printf("Listening on :%s\n", port)
http.ListenAndServe(":"+port, nil)
}
Go's http.ListenAndServe(":8080", nil) hardcodes port 8080. If Vessl sets a different port via PORT, the health check will fail. Always read os.Getenv("PORT").
Step 2 — Create the app
- In your project, click New Application.
- Select your Go repository and branch.
- Vessl detects Go — the port defaults to
8080. - Click Deploy.
Nixpacks handles go mod download and go build automatically.
Step 3 — Custom build targets
If your main package isn't at the module root (e.g. it's in cmd/server/), set the Build command in the wizard or app Settings:
go build -o app ./cmd/server
And set the Start command to:
./app
For monorepos where your Go service lives in a subdirectory, set the Root Directory to that subdirectory — all commands run relative to it.
Step 4 — Add a database
From the Add-ons tab, add PostgreSQL or MySQL. Vessl injects:
PostgreSQL:
DATABASE_URL=postgresql://<user>:<pass>@<host>:5432/<db>
DB_HOST=<internal hostname>
DB_PORT=5432
DB_DATABASE=<db name>
DB_USERNAME=<username>
DB_PASSWORD=<password>
Example with pgx:
import "github.com/jackc/pgx/v5"
conn, err := pgx.Connect(ctx, os.Getenv("DATABASE_URL"))
Example with database/sql + lib/pq:
import (
"database/sql"
_ "github.com/lib/pq"
)
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
Step 5 — Background workers
Go programs typically run background goroutines in-process, so you may not need a separate daemon. But if you want a completely isolated worker process (e.g. for a separate queue consumer binary), add a daemon from the Daemons tab:
./worker
The daemon runs in its own container with the same environment variables.
Step 6 — Go version
Nixpacks reads the go directive in your go.mod to pick the toolchain version:
module github.com/yourorg/yourapp
go 1.22
To pin a specific patch version, you can also set NIXPACKS_GO_VERSION in the Variables tab (e.g. 1.22.4).
Common issues
Build succeeds but app exits immediately
The binary probably can't bind to the port. Check that you're reading os.Getenv("PORT") and not hardcoding a port number. Also check that ListenAndServe returns an error you're logging — it may be failing silently.
go: no Go files in /app
Nixpacks couldn't find a main package at the root. Set the build command to target the correct package path: go build -o app ./cmd/yourservice.
CGO-dependent packages fail to compile
Nixpacks builds in a minimal environment. Pure-Go packages work fine, but packages with CGO dependencies (some SQLite drivers, certain crypto packages) may fail. Switch to a pure-Go alternative or use a Dockerfile build if you need CGO.