A production-ready starting point for building REST APIs in Go with:
- Gin for HTTP routing
- GORM for data access and models
- Atlas for SQL migration generation and execution
- Swagger UI for interactive API documentation
- Makefile-driven developer workflow
This repository is intended to be copied and adapted for new backend services.
- Go 1.26+
- Gin (HTTP API)
- GORM (ORM)
- PostgreSQL
- Atlas (schema diff + migration apply)
- swaggo/swag (Swagger 2.0 doc generation)
- CompileDaemon (hot reload in development)
.
|-- atlas.hcl
|-- Makefile
|-- cmd/
| `-- main.go
|-- docs/ <- generated by `make swagger`, do not edit manually
| |-- docs.go
| |-- swagger.json
| `-- swagger.yaml
|-- internal/
| |-- applications/
| | `-- users/
| | |-- controller.go
| | |-- repository.go
| | `-- service.go
| |-- config/
| | `-- base.go
| `-- database/
| |-- database.go
| `-- models/
| `-- user.go
`-- migrations/
- Layered feature organization (controller/service/repository)
- Ready-to-use user CRUD module under
/api/v1/users - Health check endpoint (
/health) - Swagger UI at
/swagger/index.htmlwith auto-generated OpenAPI spec - Environment-based app and DB configuration
- Atlas config wired to GORM models (
atlas.hcl) - Make targets for install, run, test, lint, migrations, and swagger
Install the following before starting:
- Go (1.26+)
- PostgreSQL (local or remote)
- Atlas CLI
You can install project dependencies and tools with:
make install
make install-tools- Clone and enter the repository.
- Copy environment variables:
cp .env.example .env- Update
.envvalues for your local setup. - Apply migrations:
make migrate-up- Start development server with hot reload:
make devThe API starts on port 2000 by default.
The template loads environment variables from .env automatically.
Important variables:
PORT=2000
ENV=development
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=password
DB_NAME=db_name
DATABASE_URL=postgres://postgres:password@localhost:5432/db_name?sslmode=disable&search_path=public
ATLAS_DEV_URL=postgres://postgres:password@localhost:5432/db_name_atlas?sslmode=disable&search_path=public
APP_NAME=app_name
JWT_SECRET=your_jwt_secret_keyNotes:
DATABASE_URLis used by Atlas migration apply/down/status commands.ATLAS_DEV_URLis used by Atlas when generating migration diffs.- If
DATABASE_URLis not set, the Makefile builds a URL fromDB_*values.
Run make help to see all commands. Most-used commands:
make install # Download and tidy Go modules
make install-tools # Install CompileDaemon, Atlas, and swag
make dev # Run app with auto-reload
make build # Build binary
make run # Build and run binary
make swagger # Regenerate Swagger docs from annotations
make fmt # go fmt ./...
make lint # go vet ./...
make test # go test -v ./...This template uses Atlas with the GORM provider:
- GORM models are the schema source of truth (
internal/database/models) - Atlas compares models to a dev database (
ATLAS_DEV_URL) - Atlas generates versioned SQL migration files in
migrations/ - Atlas applies migrations to your target DB (
DATABASE_URLorDB_*)
After changing models, generate a migration:
make migrate-create NAME=describe_changeExample:
make migrate-create NAME=add_user_phonemake migrate-upmake migrate-downmake migrate-statusmake migrate-resetThis drops all objects in the target database and reapplies migrations.
The API is documented with swaggo/swag (Swagger 2.0).
After starting the server, open the interactive UI at:
http://localhost:2000/swagger/index.html
Run this after adding or changing handler annotations:
make swaggerThis re-runs swag init and overwrites the generated files in docs/. Commit the updated docs/ alongside your code changes.
Annotate each handler function with swag comments, for example:
// myHandler godoc
// @Summary Short description
// @Description Full description
// @Tags group-name
// @Accept json
// @Produce json
// @Param id path string true "Resource ID"
// @Success 200 {object} models.MyModel
// @Failure 404 {object} map[string]string
// @Router /api/v1/resource/{id} [get]
func myHandler(svc Service) gin.HandlerFunc { ... }Update the main API metadata (title, version, host) in the cmd/main.go package-level comment block.
Base path: /api/v1
GET /healthPOST /api/v1/usersGET /api/v1/usersGET /api/v1/users/:idPUT /api/v1/users/:idDELETE /api/v1/users/:id
curl -X POST http://localhost:2000/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"first_name": "Ada",
"last_name": "Lovelace",
"email": "ada@example.com"
}'For a new service:
- Rename module path in
go.mod. - Replace template naming in binaries and app labels:
template-backend(module/binary/imports)- app display names in config/help text
- Create your first domain module under
internal/applications/<domain>. - Add/modify GORM models under
internal/database/models. - Generate and apply migrations.
- Wire routes in
cmd/main.go.
- Add middleware (auth, CORS, request IDs, tracing) in
cmd/main.go. - Add validation rules in controller request structs.
- Extend service layer for business logic and domain errors.
- Add repository methods for query patterns.
- Add tests for handlers, services, and repositories.
- Verify
DATABASE_URLandATLAS_DEV_URL. - Ensure PostgreSQL is running and reachable.
- Confirm credentials and database names.
- Ensure Atlas CLI is installed.
- Ensure
ATLAS_DEV_URLpoints to a valid dev database. - Ensure your models compile (
go test ./...should pass).
- The app expects a
.envfile. Copy from.env.examplefirst.
This template includes local quality commands:
make fmt
make lint
make testRecommended CI pipeline:
go mod downloadmake fmt(orgofmt -lcheck)make lintmake test
This project is licensed under the Apache License 2.0.
See LICENSE for details.