Skip to main content

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.mod at the repository root (or in your Root Directory for monorepos)

What Vessl auto-detects

When Vessl finds go.mod it sets:

SettingAuto-filled value
Build engineNixpacks
Port8080

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)
}
caution

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

  1. In your project, click New Application.
  2. Select your Go repository and branch.
  3. Vessl detects Go — the port defaults to 8080.
  4. 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:

go.mod
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.