Standard library, one file, reads PORT from the environment with a local default. Nothing here is Frontback specific.
package main import ( "fmt" "log" "net/http" "os" ) func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello from Go on Frontback") }) fmt.Println("Serving on localhost:" + port) log.Fatal(http.ListenAndServe(":"+port, nil)) }
Run it locally first; there is nothing more to it:
$ go mod init hello && go run . Serving on localhost:8080
Two things, once per machine. The CLI is a single self-contained binary with no runtime and no daemon behind it, and the login is a device code, so it works over SSH and inside a container just as well.
$ brew install frontback/tap/frontback $ frontback login open the URL it prints and enter QK7X-4M2P ✓ logged in as anna@acme.eu (organization acme)
$ brew install frontback/tap/frontback $ frontback login open the URL it prints and enter QK7X-4M2P ✓ logged in as anna@acme.eu (organization acme)
$ go install github.com/frontback/cli/cmd/frontback@latest $ frontback login open the URL it prints and enter QK7X-4M2P ✓ logged in as anna@acme.eu (organization acme)
The Go toolchain route works anywhere, whichever system you are on, and the binary is self-contained either way.
For CI, or anything else running unattended, use an API key instead of a device login: frontback login --with-token, or put FRONTBACK_TOKEN in the environment and store nothing at all. A key can be narrower than the person who made it.
frontback deploy detects Go from go.mod, compiles a static binary and ships it on a distroless base a couple of megabytes small. No Dockerfile, no YAML; open the URL it prints and your server is answering.
$ frontback deploy created project hello-go service hello-go production > building ✓ built (1.4s) ✓ artifact 3f9c21aa 6.1 MiB ✓ v1 released to production ✓ live (0.9s) https://hello-go.run.frontback.eu
Connect the repository (GitHub App, Gitea, or a deploy key), bind it to your project and track a branch per environment. A push deploys only the services the commit changed, grouped into one release: staging first, production one promote away, rollback one more.
The deploy above needed zero config. When you outgrow the defaults, frontback.json is the whole surface:
"go": "1.26""build" + "start"dist/ lands in the image, and start is shell form, so $PORT interpolates."env"GOFLAGS, build tags and CGO_ENABLED overrides go. Merged last, so it wins.Which package is the entry? cmd/<module-name> first, then the module root, then common names like server or api. More than one candidate is an error that names them, never a coin flip. And none of this is magic you have to trust: frontback pack explain prints the exact build plan before anything runs.
Make the machine bigger, or run more copies of it. Both are settings on the service in the console, and both take effect through an ordinary release, so staging sees the change before production does and a rollback is one click.
Every template deploys into your organisation as a real project, live at its own URL. Then it is yours: open the editor and change anything, or tell the AI what you want instead.
No. <code>frontback deploy</code> detects Go from your go.mod, compiles a static binary and ships it on a distroless base on its own. If you commit your own Dockerfile, it wins over the built-in Go plan.
Go 1.26 by default, with 1.25 available for maintenance. Pin it with <code>{"go": "1.26"}</code> in frontback.json or via the toolchain line in go.mod; the go directive in go.mod is treated as a minimum, not a pin, and nothing is downloaded mid-build.
Read <code>PORT</code> from the environment and fall back to 8080 locally. Frontback injects PORT at runtime and routes traffic to it, so the snippet on this page works unchanged in both places.
Yes. A known cgo dependency like mattn/go-sqlite3 automatically switches the runtime image to a glibc distroless base, and the build tells you which package caused it, with modernc.org/sqlite as the pure-Go swap if you want to stay fully static. For serverless, though, we recommend the managed libsql database: it speaks the SQLite dialect over HTTP, so there is no connection pool to exhaust and nothing to keep alive between requests.
Yes. Connect the repository (GitHub App, Gitea, or a deploy key), track a branch per environment, and every push deploys the services the commit changed as one release: staging first, production one promote away.
A small Go service fits Shared 256 MB, the smallest machine, at €4 a month always-on. Always-on starts on the Pro plan (€19 a month); the Free plan runs services on demand and stops them when idle. Every price is on the pricing page, not behind a sales call.
On our own data servers in the EU. EU hosting is the default on every plan, not a paid add-on, which is usually the answer your compliance team is looking for.
Go beyond what seems possible.