go-starter: an opinionated Go REST API template you update by merging
An opinionated production-ready SQL-/Swagger-first RESTful JSON API written in Go, highly integrated with VSCode DevContainers by allaboutapps.
At a glance
- What is it?
- go-starter is a PostgreSQL first REST API template for Go with SQLBoiler models, sql-migrate migrations, go-swagger specs, an auth package and a Docker Compose development container. Its value is the pre-wired toolchain, and its cost is that every opinion is already decided for you.
- Who is it for?
- go-starter fits a team that wants a PostgreSQL backed JSON API running inside a devcontainer on day one and can accept the Echo router, sql-migrate, SQLBoiler, cobra and go-swagger choices it ships with. It is the wrong base for a service that needs a different datastore, a gRPC or GraphQL surface, or a dependency set your organisation forbids.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 65 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the template decides for you before you write a line
Most Go projects begin with an empty module and a sequence of small choices that quietly turn into architecture. go-starter removes that sequence. The template ships a working service with a router, a database layer, an auth package, a CLI, observability endpoints and a container setup, all wired together and running.
The stack is specific, and specificity is the point. HTTP is handled by Echo v4, configuration is read through Viper, the command layer comes from spf13/cobra, logging is rs/zerolog, and metrics come from the Prometheus client. Authentication uses OAuth 2.0 Bearer Tokens with password hashing via argon2id. If any of that matches your company standard, you save weeks. If your company standard is net/http with a different router, or you are on a managed secrets service rather than local env files, the template becomes something you rewrite rather than something you extend.
The layout follows the golang-standard/project-layout convention, with top-level directories such as api, cmd, internal, migrations, scripts, test and web. That convention has detractors in the Go community, but it does mean the skeleton is familiar to anyone who has opened a large Go service before.
The SQL-first loop through sql-migrate, SQLBoiler and go-swagger
The core workflow is that you change the database and the API contract, then let generators rebuild the Go code around them. Migrations come from rubenv/sql-migrate and live in the migrations directory. Models are generated by SQLBoiler, and the go.mod file pins github.com/aarondl/sqlboiler/v4 at v4.19.5 with a matching dbconfig.yml and sqlboiler.toml. The API spec is go-swagger, which generates swagger.yml, request and response structs, and validation functions at compile time.
That ordering has a consequence worth naming. Because the spec drives generation, the Swagger file is a source artifact you maintain, not a document you publish after the fact. The repository even carries a .spectral.yml file, which is the linter configuration for OpenAPI documents, so the spec is checked rather than merely written. The README states the Swagger v2 schema is previewed live through SwaggerUI, and a build badge points at a live Swagger validator for the master branch.
Compare that with the common alternative of hand-written structs and a hand-maintained OpenAPI file. There, the two drift apart and someone rediscovers the mismatch during a client integration. Here the drift shows up in a generator diff. The cost is that every change to a payload shape touches the spec first, and the spec has its own syntax that your team has to learn.
The devcontainer runs the app, PostgreSQL and the test database together
Development happens inside a Docker Compose stack defined in docker-compose.yml, and VSCode attaches to it through the Remote Containers extension. The requirements list is explicit: Docker CE 19.03 or above, Docker Compose 1.25 or above, and the ms-vscode-remote.remote-containers extension. The project documentation also states that a local Go toolchain is no longer required for this setup, because the compiler lives in the container.
The compose file shows how the pieces are arranged. The service builds from the Dockerfile with target development, maps port 8080 on the host to 8080 in the container, and runs as the development user so that files written into the mounted working directory keep workable permissions. The project directory is mounted at /app with the delegated consistency option, which the comments explain is what avoids stale reads on macOS. Cached Go package downloads, tmp directories, VSCode server extensions and the bash history file all live in named volumes rather than on the host filesystem, which is what keeps rebuilds fast and container recreations cheap.
The service also declares dependencies on postgres and integresql, and the environment block sets PGDATABASE, PGUSER, PGPASSWORD, PGHOST and PGPORT for the working database. Everything a new contributor needs is therefore one extension and one compose file, and the cost is that Docker becomes a hard prerequisite for every build and test, including on a machine where running the container is inconvenient.
First run: template repository, then the compose file that defines the world
The entry point is the GitHub template feature. The quickstart tells you to create a new git repository from the template repository, and you then start with a single initial commit in your own repository. That detail matters for the upgrade path discussed later, because your repository is a copy rather than a fork.
Once you have the code, the environment is described by the compose file. This excerpt shows the shape of it:
services:
service:
build:
context: .
target: development
ports:
- "8080:8080"
working_dir: &PROJECT_ROOT_DIR /appThe build target is development, which the Dockerfile defines as a stage based on the official Go image:
FROM golang:1.27.0-trixie AS developmentTwo environment settings inside that stage are worth knowing about. The first suppresses interactive package prompts, the second turns on parallel Make jobs:
ENV DEBIAN_FRONTEND=noninteractive
ENV MAKEFLAGS="-j 8 --no-print-directory"The module itself is declared in go.mod, and it declares the Go version the project targets:
module allaboutapps.dev/aw/go-starter
go 1.27.0Your first real use is then the make workflow: open the project in VSCode, let the devcontainer attach, and run make help to see every target and its description. From there the default make target runs the sql, swagger, go-generate-handlers, go-format, go-build and lint steps in order.
IntegreSQL gives each test run its own PostgreSQL instance
Integration testing is the part of the template that goes beyond scaffolding. The project integrates IntegreSQL, an allaboutapps tool, for fast, concurrent and isolated integration testing against real PostgreSQL databases. The dependency list includes github.com/allaboutapps/integresql-client-go at v1.0.0, and the compose file starts an integresql service alongside postgres.
The difference from a shared test database is isolation. With IntegreSQL, a test can provision a database of its own, run migrations against it, and drop it afterwards, so parallel test runs do not collide over table state. The alternative approach, pointing tests at one long lived test database and truncating between runs, is simpler to set up and breaks as soon as two suites run at the same time.
A second DevContainer service exists for IntegreSQL, and MailHog is included for SMTP based email testing, so a signup flow can be exercised without sending real mail. Prometheus client metrics and the liveness and readiness endpoints at /-/healthy and /-/ready are also wired in, and the initial migration set covers auth tokens for access, refresh and password reset, a generic user model, an app_user_profile model, push notification tokens, and a health check sequence for writable checks.
The auth package and push notifications arrive already implemented
Authentication is the part reviewers look at first, and go-starter answers with a tested auth package and an OAuth2 RESTful JSON API that is meant to be extended. Passwords are hashed with argon2id via the alexedwards/argon2id package, and the OAuth 2.0 Bearer Token scheme from RFC 6750 is what clients present. The migration set carries the three token families a typical session needs, access, refresh and password reset, along with a generic user model and a bare bones app_user_profile.
Push notifications come with a mock provider and an FCM provider for Firebase Cloud Messaging, and push tokens are stored in the database. The mock provider matters for tests: a notification test should not depend on a Firebase project.
What is missing is as telling as what is present. The template does not document refresh token rotation policy, revocation behaviour, session storage, or multi tenant scoping. The SQLite and MySQL angle is likewise absent: the dependency list uses github.com/lib/pq, the compose file defines a postgres service, and the SQL layer is written for PostgreSQL. Porting this to another database is a rewrite of the data layer, not a configuration change.
Make targets, a multi-stage Dockerfile and CI scanning baked in
The build system is a Makefile with parallel jobs enabled, and the project notes that a full rebuild takes seconds. The default target chains the pre build steps, formatting, compilation and linting. The pre build step is the interesting one, because it runs sql, swagger and go-generate before any Go code is compiled, which is how the database schema and the API spec stay in step with the source.
The generated artefacts are conventional. Formatting is handled by go fmt, the binary lands in bin/app, and linting runs golangci-lint with a .golangci.yml configuration in the repository root. The Makefile also carries an info target that prints the spec database state, handler information and go.mod updates, and the lint target depends on a set of checks named check-gen-dirs, check-script-dir, check-handlers and check-embedded-modules-go-not.
The Dockerfile is multi-staged and named in the order development, builder, app, and the development stage is built from golang:1.27.0-trixie. The go.mod file requires go 1.27.0, which sets the floor for anyone building outside the container. Security tooling is part of the default workflow rather than an add-on: the image installs the Aqua Trivy repository, the Makefile has a trivy target wired into the all target, and the repository root holds a .trivyignore. Continuous integration runs on Drone and Woodpecker, with .drone.yml and .woodpecker directories present, and changelogs are managed with changie through .changie-go-starter.yaml and a dedicated CHANGELOG-go-starter.md.
No releases, a wiki for the reasoning, and an opinionated price
The repository has no GitHub releases at all, so versioned artifacts are not part of the distribution model. The last push was on 2026-08-20, and the default branch is master. Updates therefore arrive by merging the template repository into your project, a workflow the project describes in its own section, and by pulling the upstream changes into a copy of the template rather than by pulling a tagged release.
That merge-based upgrade path is the central trade-off of the whole project. You get a complete working backend immediately, but you also inherit every decision the maintainers made, and every future upstream change arrives as a merge conflict in your own repository when your code has diverged in the same files. The repository root makes the mechanism visible: README-go-starter.md is the template version of the readme, separate from your own README.md, and the .changes-go-starter directory holds the upstream changelog entries that come with those merges.
The licence is MIT, which is the easy case for adoption: you can modify the template and ship a closed source product built on it, and the licence obligation is to keep the copyright notice and licence text. The project describes itself as opinionated and production-ready by design, and points to a wiki FAQ for the history and the reasoning behind the choices. Read that FAQ before deciding, because the opinions are the product and the opinions are PostgreSQL, Echo, Swagger v2, sql-migrate and DevContainers.
Editorial conclusion
go-starter fits a team that wants a PostgreSQL backed JSON API running inside a devcontainer on day one and can accept the Echo router, sql-migrate, SQLBoiler, cobra and go-swagger choices it ships with. It is the wrong base for a service that needs a different datastore, a gRPC or GraphQL surface, or a dependency set your organisation forbids. Before you commit, run make help inside the container, then generate one SQLBoiler model and one swagger.yml change and read the diff, because the generated code and the go-swagger validation functions are the parts of this template you will inherit rather than choose.
Frequently asked questions
Do I need Go installed locally to work on a go-starter project?
No. The README states that a local installation of the Go tool-chain is no longer required when using the devcontainer setup, and that it works with Linux, macOS and Windows. You do need Docker CE 19.03 or above, Docker Compose 1.25 or above, and the VSCode Remote Containers extension.
How does go-starter handle database schema changes and API contracts?
Migrations come from rubenv/sql-migrate, PostgreSQL models are generated by SQLBoiler, and go-swagger generates swagger.yml plus request and response validation functions at compile time. The Makefile runs the sql, swagger and go-generate targets before building, so the schema and the spec drive the Go code.
Is go-starter suitable for a non-PostgreSQL backend or a GraphQL API?
It is built around PostgreSQL. The dependency list includes github.com/lib/pq, the compose file defines a postgres service, and the included migration set is written for PostgreSQL. The API surface is RESTful JSON with Swagger v2, and the documentation does not describe GraphQL support.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/allaboutapps-go-starter)Was this useful?