A Go REST API starter built with Chi, pgx, JWT auth, Swagger, Prometheus metrics, and PostgreSQL.
Template note: after forking, update the CI badge URL to point at your repo.
- Chi router
- pgx/v5 PostgreSQL driver and pool
- golang-migrate migrations
- JWT authentication
- Role-aware authorization (
user/admin) - Password reset and password change flows
- Zerolog structured logging
- Prometheus metrics at
/metrics - Swagger UI at
/swagger/index.html - Dockerfile and
docker-compose.yml - GitHub Actions CI for test, lint, and build
- Optional Redis-backed queue components included in the repo
This repository is a starter template, but the checked-in app is also a functioning example API.
POST /api/auth/registerPOST /api/auth/loginPOST /api/auth/request-password-resetPOST /api/auth/reset-passwordPOST /api/auth/change-password(requires JWT)GET /api/users/me(requires JWT)GET /api/users/{id}(owner or admin)PUT /api/users/{id}(owner or admin)GET /api/users(admin only)POST /api/users(admin only)DELETE /api/users/{id}(admin only)PUT /api/users/{id}/role(admin only)GET /api/healthGET /metrics- Swagger UI at
/swagger/index.html
- Queue abstractions and workers under
cmd/api/queue/ - Queue admin handlers under
cmd/api/handlers/queue_handler.go - Queue helper CLIs such as
cmd/test-queueandcmd/queue-monitor
The queue packages are real and testable, but the main API server in cmd/api/main.go / cmd/api/routes.go does not currently initialize a queue or mount queue admin routes.
- Go version: 1.25+
- Local development docs in this repo recommend PostgreSQL 18
- Current Docker Compose and GitHub Actions CI use PostgreSQL 16 images
So the practical compatibility story right now is: local Postgres 18 is recommended, while the checked-in container/CI baseline is Postgres 16.
cmd/
api/ # Main API app
queue-monitor/ # Queue inspection CLI
test-queue/ # Queue demo/test CLI
docs/ # Swagger output and supporting guides
migrations/ # SQL migrations
tests/ # Integration tests
Before you begin, ensure you have:
- Go 1.25+
- PostgreSQL (18 recommended for local dev; 16 is what Docker/CI currently run)
- Git
- Docker (optional, for containerized dev and helper services)
Verify your installation:
go version
psql --versiongit clone https://github.com/justyn-clark/go-chi-postgres-starter.git
cd go-chi-postgres-starter
go mod tidycp .env.example .envEdit .env as needed. Minimum local settings:
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/go_api_starter?sslmode=disable
JWT_SECRET=dev-secret-change-in-production
PORT=8080
ENVIRONMENT=development
LOG_LEVEL=infoGenerate a real JWT secret for non-throwaway use:
openssl rand -base64 32createdb go_api_starterAlternative:
psql -d postgres -c 'CREATE DATABASE go_api_starter;'go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/go_api_starter?sslmode=disable"
make migrate-upmake runAPI docs will be available at:
- API: http://localhost:8080
- Health: http://localhost:8080/api/health
- Swagger UI: http://localhost:8080/swagger/index.html
- Metrics: http://localhost:8080/metrics
docker-compose.yml starts:
- Postgres on host port
5434 - Redis on host port
6379 - API on host port
8080
Start everything:
docker compose up -d --buildWhen using Docker for the database from your host shell, use:
export DATABASE_URL="postgresql://postgres:postgres@localhost:5434/go_api_starter?sslmode=disable"If you only want the database container for local app development:
make devThat target starts the Compose Postgres service and then runs the API locally with live reload.
Primary auth is JWT-based:
- Register with
POST /api/auth/register - Log in with
POST /api/auth/login - Send
Authorization: Bearer <token>
If API_ACCESS_TOKEN is set, requests may also authenticate with:
X-API-Token: <token>
This is useful for service-to-service access to routes protected only by the JWT middleware.
Important: admin-only routes still require admin role context. The API access token bypass does not establish a user role, so it does not grant admin access to endpoints like GET /api/users.
- Public:
GET /api/healthPOST /api/auth/registerPOST /api/auth/loginPOST /api/auth/request-password-resetPOST /api/auth/reset-password
- Authenticated user:
POST /api/auth/change-passwordGET /api/users/me
- Owner or admin:
GET /api/users/{id}PUT /api/users/{id}
- Admin only:
GET /api/usersPOST /api/usersDELETE /api/users/{id}PUT /api/users/{id}/role
Register:
curl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","full_name":"Test User","password":"password123"}'Login:
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password123"}'Get your own profile with the returned token:
curl -X GET http://localhost:8080/api/users/me \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Common targets:
make run
make run-dev
make dev
make stop
make fmt
make vet
make lint
make test
make test-coverage
make migrate-up
make migrate-down
make migrate-status
make swagger
make docker-up
make docker-downThere is also a mirrored justfile, so you can use just run, just test, etc.
Repo tests currently live primarily in tests/api_test.go.
Run them with:
make testFor coverage:
make test-coverageCI currently runs:
- tests with PostgreSQL 16 service container
- golangci-lint
- binary build
make migrate-create NAME=add_users_table
make migrate-up
make migrate-down
make migrate-statusGenerate Swagger artifacts:
make swaggerThen open:
http://localhost:8080/swagger/index.html
- Quick Start Guide
- Setup Guide
- Authentication Guide
- Testing Guide
- Deployment Guide
- Postman Setup Guide
- Postman Get Users Guide
- Goroutines Guide
- Queue Usage Guide
- Contributing
If you use this starter for a new repo, update:
go.modmodule path- import paths containing
github.com/yourusername/go-chi-postgres-starter - GitHub badge URLs
- author/contact metadata as needed
Justyn Clark
- GitHub: @justyn-clark
- Email: justyn-clark@users.noreply.github.com
MIT — see LICENSE.