Deploy Go
Deploy a Go application on Out Plane, with a static build and a managed database.
This guide deploys a Go web service and connects it to a managed PostgreSQL database. For the shared deploy flow, see Deploy from GitHub.
Prepare Your App
Listen on 0.0.0.0
Read the port from the environment and bind all interfaces. The :+port form binds
0.0.0.0. Do not bind 127.0.0.1 or localhost, or the app is unreachable.
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("listening on 0.0.0.0:%s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))For Gin use r.Run("0.0.0.0:" + port), and for Fiber use app.Listen("0.0.0.0:" + port).
Build
Pin the Go version with the go directive in go.mod, and commit go.sum. A static
binary gives the smallest, most reliable image:
CGO_ENABLED=0 go build -ldflags="-s -w" -o serverCGO_ENABLED=0 produces a fully static binary. -ldflags="-s -w" strips debug info.
Deploy
Create an application from your repository. Buildpacks detects Go from go.mod and
builds it with no Dockerfile. For full control, a multi stage Dockerfile keeps the
final image tiny:
FROM golang:1.24-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /server ./...
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=build /server /server
EXPOSE 8080
CMD ["/server"]Install ca-certificates in the final image, or TLS calls (including SSL database
connections) will fail.
Connect a Database
Create a managed PostgreSQL database and copy its connection
string into a DATABASE_URL environment variable.
import _ "github.com/jackc/pgx/v5/stdlib"
db, err := sql.Open("pgx", os.Getenv("DATABASE_URL"))Connections require SSL, so make sure the string includes ?sslmode=require. pgx
honors it.
Run Migrations
Out Plane has no pre deploy hook. Run your migration tool (such as golang-migrate,
goose, or atlas) once from the browser terminal, or fold it
into the start command:
sh -c "migrate -path migrations -database $DATABASE_URL up && /server"Production Notes
- Bind
0.0.0.0, and readPORTrather than hardcoding it. - Use
CGO_ENABLED=0for a static binary unless you genuinely need cgo. - Bundle templates and static assets with
//go:embed, orCOPYthem in theDockerfile, so a slim image still has them.