EthioDeploy/Docs
HomePricing
Overview

Overview

  • Getting started
  • How deploys work

Frameworks

  • Framework guides

Configuration

  • Web services & background workers
  • Environment variables
  • Addons
  • Database & Redis tools
  • Branch deployments
  • Custom domains
  • Analytics

Domains

  • Buying a domain

Agent mode

  • Agent mode
  • Agent plans & credit

CLI

  • Command-line tool

Account

  • Team access
  • Billing

Help

  • Troubleshooting
  • Still stuck?
Deploy guides
  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Firebase Studio
  • Claude Code & Cursor
Compare
  • AI coding agent
  • Hosting in Ethiopia
  • vs Heroku
  • vs Vercel
  • vs Render
  • vs Railway
  • vs Fly.io
  • vs Netlify
  • Heroku alternatives
Deploy guidesGo

Deploy a Go app

Go apps are detected from go.mod and compiled into a single binary. Read PORT, add a health route, and push.

Last updated October 23, 2026

Detected by
go.mod
Install
go mod download
Build
go build -o out (or ./cmd/<name>)
Start
./out

These are the defaults. Override any of them in Settings → Build.

Listen on the PORT variable

Read the port from the environment: http.ListenAndServe(":"+os.Getenv("PORT"), mux). Leave the host empty so the server listens on every interface. A server bound to 127.0.0.1 fails the health check.

Prepare your app

We detect Go from go.mod, download modules, and build a binary named out:

  • A main.go at the repo root is built with go build -o out.
  • With no root main.go, the package under cmd/<name> is built. If you have several, set the Build command, for example go build -o out ./cmd/api.
  • CGO_ENABLED=0 is set, so the binary is static. Packages that need cgo (such as mattn/go-sqlite3) won't build; use a pure-Go alternative like modernc.org/sqlite, or set CGO_ENABLED=1 as an env var.
package main

import (
	"net/http"
	"os"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok"))
	})
	http.ListenAndServe(":"+os.Getenv("PORT"), mux)
}

If go.mod asks for a newer Go than the build image has, Go downloads that toolchain during the build. This needs the full version in go.mod (go 1.25.0, not go 1.25), which is what go mod init and go get go@latest write.

Files your binary reads at runtime (templates, static assets) are copied with the repo, but //go:embed keeps everything in the binary and avoids path surprises.

Health check

Every deploy requests your health check path (/ by default) and only goes live once it returns a 2xx or 3xx status. The platform keeps checking it after that. If / returns 404 or needs a login, add a route like /healthz that returns 200 and set it as the Health Check Path in Settings. Otherwise the deploy fails and the previous version keeps serving.

Add a database

Add a Postgres addon and DATABASE_URL is injected automatically. pgx accepts it as-is:

pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))

Run migrations (goose, golang-migrate, Atlas) when the binary starts, or in front of it in the Start command.

Graceful shutdown

On each deploy, the old container is stopped once the new one is healthy. Catch SIGTERM and call Shutdown so requests in flight finish:

srv := &http.Server{Addr: ":" + os.Getenv("PORT"), Handler: mux}
go srv.ListenAndServe()

ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt)
defer stop()
<-ctx.Done()
srv.Shutdown(context.Background())

Workers and bots

A Go program with no HTTP server (a queue consumer, a Telegram bot) runs as a Background Worker: set the service type in Settings. It skips the HTTP health check, and the old instance is stopped before the new one starts, so two copies never poll at once.

Deploy

  1. Sign in with GitHub and install the EthioDeploy app on the repo.
  2. Click “New Project” and pick the repo.
  3. Watch the build in the dashboard. When the health check passes, your app is live at <project-slug>.ethiodeploy.com. Every push to the default branch redeploys, and the old version keeps serving until the new one is healthy.

Troubleshooting

Build fails: go: download go1.25 for linux/amd64: toolchain not available

Cause: go.mod asks for a newer Go than the build image has, written without a patch number, so Go can't find a toolchain to download.

Fix: Write the full version in go.mod, for example go 1.25.0. Go then downloads that toolchain during the build.

Build fails: no Go files in the repo root

Cause: main lives in a subfolder that isn't under cmd/.

Fix: Set the Build command to go build -o out ./path/to/main.

cgo or sqlite3 errors at build or start

Cause: CGO_ENABLED=0 is set by default.

Fix: Use a pure-Go driver, or set CGO_ENABLED=1.

Health check times out

Cause: The server binds 127.0.0.1 or a fixed port.

Fix: Listen on ":"+os.Getenv("PORT").

Deploy fails: GET / returned 404

Cause: / doesn't return a 2xx or 3xx status, so the health check never passes.

Fix: Add /healthz and set it as the Health Check Path.

Still stuck? Check the deployment's build log in the dashboard, or see Troubleshooting.

Questions

Can I host a Go app for free?

Yes. The Free plan runs one project with a 512 MB Postgres or Redis. It sleeps after 30 minutes without traffic. A Go binary's small memory footprint fits the Free plan's 256 MB container well.

Do I need a Dockerfile?

No. go.mod is detected and the binary is built and started for you. If your repo has a Procfile, its web line is used as the start command.

Does it work with Gin, Echo, Fiber or Chi?

Yes. They all build the same way. Make the router listen on the PORT environment variable.

Ready to deploy? Sign in with GitHub and pick your repo. No Dockerfile, no YAML.

Other framework guides

Next.jsNode.jsPythonSvelteKitLovableBoltClaude Code & CursorDjangoFastAPIFlaskLaravelExpressFirebase Studio

See the full docs for custom domains, env vars, addons, and billing.

On this page

  • Prepare your app
  • Health check
  • Add a database
  • Graceful shutdown
  • Workers and bots
  • Deploy
  • Troubleshooting
  • Questions

Product

  • Pricing
  • Documentation
  • AI coding agent
  • Agent mode docs
  • Domains
  • Hosting in Ethiopia

Deploy guides

  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Firebase Studio
  • Claude Code & Cursor

Compare

  • EthioDeploy vs Heroku
  • EthioDeploy vs Vercel
  • EthioDeploy vs Render
  • EthioDeploy vs Railway
  • EthioDeploy vs Fly.io
  • EthioDeploy vs Netlify
  • Heroku alternatives

Company

  • About
  • Support
  • Contact
  • Terms
  • Privacy

EthioDeploy: agentic first development and deployment, started in Ethiopia, built for developers everywhere.