MCPcopy Create free account
hub / github.com/NawafSwe/go-service-starter-kit

github.com/NawafSwe/go-service-starter-kit @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
619 symbols 2,006 edges 137 files 225 documented · 36% updated 5mo agoapi/v1.0.1 · 2026-03-08★ 44

Browse by type

Functions 465 Types & classes 154
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Go Gopher

go-service-starter-kit

A production-ready Go backend template for services that do more than serve HTTP.

Go Version License CI

One binary. Multiple processes. Zero boilerplate.


Why this template exists

Most Go service templates stop at "here is how to start an HTTP server." Real production services are more complex: they run background jobs, consume Kafka or RabbitMQ messages, expose gRPC endpoints for internal traffic, and handle one-off data migrations — all sharing the same business logic and infrastructure.

This template distils patterns and lessons from multiple production Go services. Rather than reflecting a single codebase, it combines the architectural decisions that proved scalable across different domains and team sizes into one reusable starting point that:

  • Ships all process types (HTTP, gRPC, consumer, jobs) from a single binary, selected at runtime
  • Enforces a clean-layered architecture — domain → business → endpoint → transport — so your code stays testable as it grows
  • Provides JWT authentication baked in for HTTP, gRPC, and message consumers out of the box
  • Wires OpenTelemetry tracing, structured logging, and metrics from day one, so observability is never an afterthought
  • Keeps infrastructure concerns in internal/ and your domain in internal/app/, making the boundary between your code and plumbing explicit

The template is intentionally opinionated. It picks go-kit, gorilla/mux, sqlx, zerolog, and viper — a stack that has been proven at scale. You are free to swap any layer out.


What's inside

go-service-starter-kit/
│
├── cmd/
│   ├── main.go               # Entry point — flag parsing, process dispatch
│   └── app/
│       ├── registry.go       # Long-running process registry
│       ├── http.go           # HTTP process wiring
│       ├── grpc.go           # gRPC process wiring
│       ├── consumer.go       # Message consumer wiring
│       └── job.go            # One-time job registry
│
├── api/                      # Proto module (github.com/nawafswe/go-service-starter-kit/api)
│   ├── go.mod                # Nested Go module — import with: go get …/api@v1.0.0
│   └── proto/grpc/v1/
│       ├── example.proto     # proto3 service definitions
│       └── gen/              # Generated Go stubs (pb.go + grpc.pb.go)
│
├── internal/
│   ├── auth/                 # JWT (ClaimsParser) + bcrypt password hashing
│   ├── clients/
│   │   └── db/
│   │       ├── postgres/     # OTel-traced PostgreSQL pool (sqlx + lib/pq)
│   │       ├── mysql/        # OTel-traced MySQL pool (sqlx + go-sql-driver)
│   │       └── mongodb/      # OTel-traced MongoDB client (mongo-driver)
│   ├── config/               # Viper loader — YAML + .env + env vars
│   ├── db/                   # Database-agnostic pagination (Page, PageResult)
│   │   └── sqlorder/         # SQL ORDER BY builder with column sanitisation
│   ├── gokit/
│   │   ├── http/             # go-kit HTTP handler factory
│   │   ├── grpc/             # go-kit gRPC handler factory
│   │   └── consumer/         # go-kit endpoint wrapper for message consumers
│   ├── httperrors/           # Reusable HTTP error types (400, 401, 403, 404, 409, 500)
│   ├── httpx/                # Resilient HTTP client (retry, circuit breaker, OTel)
│   │   └── mock/             # MockDoer for unit tests
│   ├── grpcx/                # Resilient gRPC client (retry, circuit breaker, OTel)
│   │   └── mock/             # MockInvoker for unit tests
│   ├── middleware/
│   │   ├── http.go           # JWT HTTP middleware (AuthRequired / AuthOptional / AuthMock)
│   │   ├── grpc.go           # JWT gRPC interceptors + logging + tracing interceptors
│   │   ├── consumer.go       # JWT consumer middleware (works with any message broker)
│   │   ├── gokit.go          # Timeout + sliding-window rate limiter (go-kit)
│   │   └── logging.go        # Transport-aware logging with sensitive-field masking
│   ├── observability/
│   │   ├── logger/           # zerolog-backed structured, context-aware logger
│   │   ├── tracing/          # OTel trace provider (OTLP gRPC exporter)
│   │   └── metric/           # OTel metric Reporter
│   ├── text/                 # NonLoggable — redacts sensitive strings from logs and JSON
│   ├── worker/
│   │   ├── http.go           # HTTP worker — graceful shutdown on SIGINT/SIGTERM
│   │   ├── grpc.go           # gRPC worker — graceful shutdown
│   │   ├── consumer.go       # Consumer worker — graceful shutdown
│   │   └── mock/             # MockMessageConsumer for unit tests
│   │
│   └── app/                  # Your domain code lives here
│       ├── domain/           # Entities + sentinel errors
│       ├── business/         # Use cases — one file per operation
│       ├── repositories/     # Data access layer (sqlx + PostgreSQL)
│       ├── endpoint/v1/      # go-kit endpoint adapters
│       └── transport/
│           ├── http/         # HTTP — server, bootstrap, v1 encode/decode, JSON:API error encoder
│           ├── grpc/         # gRPC — server, bootstrap, v1 handler + encode/decode via go-kit
│           └── consumer/     # Consumer — bootstrap, v1 message decode, map-based endpoint routing
│
├── test/                        # Integration + load tests (isolated from internal/)
│   ├── .env.integration         # Test-specific environment variables
│   ├── pkg/
│   │   ├── suite/               # Test suite — per-test DB isolation, token helpers, HTTP client
│   │   └── testdb/              # Isolated PostgreSQL provisioning (golang-migrate)
│   ├── api/
│   │   └── http/
│   │       └── example/         # Example endpoint integration tests + testdata
│   └── load/                    # k6 load test scripts
│       ├── data/                # Request payload templates (JSON)
│       ├── pkg/                 # Shared config, utilities, gRPC client wrapper + proto
│       ├── http_*.js            # HTTP endpoint load tests
│       └── rpc_*.js             # gRPC endpoint load tests
│
├── scripts/
│   └── k6.sh                   # k6 runner — lists and runs load tests
│
├── db/
│   ├── initdb.d/             # PostgreSQL init scripts (user/schema bootstrap)
│   ├── load/                 # Seed / fixture data
│   └── migrations/           # SQL migration files (golang-migrate)
│
├── docs/
│   ├── asyncapi/             # AsyncAPI 3.0 spec — event / message contracts
│   ├── img/                  # Assets used in documentation
│   └── openapi/              # OpenAPI 3.1 spec + oapi-codegen config
│
├── .github/workflows/ci.yml  # CI — build + unit tests + integration tests on every push / PR
├── docker-compose.yml        # postgres, kafka, otel-collector (profile-based)
├── otel-collector-config.yaml # OpenTelemetry Collector configuration
├── config.yaml               # Default configuration
├── .env.sample               # Environment variable template
├── Dockerfile                # Production multi-stage build
├── Dockerfile.dev            # Development build
├── Makefile                  # Developer commands
└── LICENSE

Architecture overview

The design follows a strict dependency flow — outer layers depend on inner layers, never the reverse:

Request
   │
   ▼
Transport          (HTTP / gRPC / Consumer)
   │  encode / decode
   ▼
Endpoint           (go-kit adapter — applies middleware: auth, timeout, rate-limit, logging)
   │  typed request
   ▼
Business           (use-case handler — pure Go, no framework dependency)
   │  repository interface
   ▼
Repository         (sqlx + PostgreSQL — implements the interface)
   │
   ▼
Database

Each layer communicates through interfaces, which means every layer can be unit-tested in isolation with mocks — no database, no HTTP server required.


Getting started

Prerequisites

  • Go 1.25+
  • Docker + Docker Compose

1. Clone, rename, and configure

git clone https://github.com/nawafswe/go-service-starter-kit.git my-service
cd my-service

# Rename the Go module to match your repository
go mod edit -module github.com/<your-org>/<your-service>
go mod tidy

# Copy sample env and fill in your values
make env

Important: update all import paths after renaming the module. A global search-and-replace of github.com/nawafswe/go-service-starter-kit with your new module path covers everything.

2. Start the database and run migrations

docker compose up postgres -d
docker compose up migrate      # runs all pending migrations

3. Build and run

make build

./bin/app http       # HTTP server  (default :8080)
./bin/app grpc       # gRPC server  (default :50051)
./bin/app consumer   # message consumer
./bin/app <job>      # one-time job

Makefile commands

Command Description
make build Build the binary to ./bin/app
make build-docker Build the production Docker image
make run-http Build and run the HTTP server
make run-grpc Build and run the gRPC server
make run-consumer Build and run the message consumer
make env Copy .env.sample to .env if it doesn't exist
make clean Remove built binaries
make migrate-up Run all pending database migrations
make migrate-create name=<name> Create a new migration file
make lint Run golangci-lint (via Docker)
make test Run unit tests with coverage
make test-integration Run integration tests
make test-load name=<test> Run a k6 load test (e.g. K6_VUS=100 make test-load name=http_post_create_example)
make test-load-list List available k6 load tests
make fmt Format code (gci + gofumpt)
make generate Run go generate across all packages
make generate-contracts Regenerate HTTP types from OpenAPI spec
make docker-start Start the Docker environment
make docker-stop Stop the Docker environment
make docker-clean Remove Docker containers and volumes
make docker-restart Restart the Docker environment

Configuration

Configuration is merged from three sources (highest priority first):

Priority Source Format
1 (highest) OS environment variables KEY__NESTED=value
2 .env file KEY__NESTED=value
3 (lowest) config.yaml YAML

The __ double-underscore is the struct delimiter — DB__DSN maps to Config.DB.DSN.

Required variables:

Variable Description
DB__DSN PostgreSQL connection string
JWT__SECRET HMAC-SHA256 signing secret
HTTP__PORT HTTP listen port

Endpoint-level configuration

Each endpoint can be individually tuned for timeout and rate limiting in config.yaml:

ENDPOINTS:
  EXAMPLE_CREATE:
    DEADLINE: 5s               # request timeout
    RATE_LIMITER:
      INTERVAL: 1m             # sliding window duration
      LIMIT: 100               # max requests per window

These values are applied as go-kit middleware in each transport's bootstrap layer.


Docker Compose profiles

Services are organised into profiles so you only run what you need:

Profile Services Command
(default) postgres, migrate docker compose up
app app-http, app-grpc, app-consumer docker compose --profile app up
kafka kafka (single-node KRaft) docker compose --profile kafka up
observability otel-collector docker compose --profile observability up

Combine profiles as needed: docker compose --profile app --profile kafka --profile observability up


Extending the template

Rename the domain

Replace internal/app/ with your service name (e.g. internal/orders/) and update the import paths. The shared infrastructure packages under internal/ stay unchanged.

Add a new use case

internal/<domain>/
  domain/            <- add your entity + any new sentinel errors
  repositories/<x>/  <- add your SQL queries
  business/<op>/     <- add your handler (CreateXxx, UpdateXxx, ...)
  endpoint/v1/       <- add your go-kit endpoint adapter
  transport/http/v1/ <- add your encode/decode codec

Then wire it in internal/app/transport/http/bootstrap/: 1. handler_initializer.go — instantiate the handler 2. router_v1_register.go — mount the route

Add a new process

// cmd/app/my_process.go
type MyProcess struct{}
func (MyProcess) Register(args ProcessArgs) (Process, error) { ... }

// cmd/app/registry.go
var RegistryProcessesMap = map[string]ProcessRegistry{
    "http":       NewHTTPServerProcess(),
    "my-process": MyProcess{},  // <- add here
}

Add a one-time job

// internal/app/jobs/my_job.go
type MyJob struct{}
func (MyJob) Schedule(args app.ProcessArgs) error { ... }

// cmd/app/job.go
var JobsMap = map[string]Scheduler{
    "my-job": MyJob{},
}

Run it with: ./bin/app my-job

Implement the message consumer

The consumer transport is broker-agnostic — it defines a MessageRouter that maps message types to go-kit endpoints with decode functions. You provide the broker integration:

```go // internal/app/transport/consumer/consumer.go — Start() reader := kafka.NewReader(kafka.ReaderConfig{ Brokers: c.cfg.Consumer.Brokers, GroupID: c.cfg.Consumer.GroupID, Topic: c.cfg.Consumer.Topics[0], }) defer reader.Close()

for { msg, err := reader.ReadMessage(ctx) if err != nil { if errors.Is(err, context.Canceled) { return nil } return fmt.Errorf("consumer: read message: %w", err)

Extension points exported contracts — how you extend this code

browse all types & interfaces →

Core symbols most depended-on inside this repo

browse all functions →

Shape

Function 267
Method 198
Struct 116
Interface 24
FuncType 10
TypeAlias 4

Languages

Go98%
TypeScript2%

Modules by API surface

api/proto/grpc/v1/gen/example.pb.go61 symbols
internal/observability/logger/logger.go33 symbols
api/proto/grpc/v1/gen/example_grpc.pb.go30 symbols
internal/config/config.go16 symbols
internal/app/transport/http/v1/example_encode_decode.go14 symbols
test/pkg/testdb/testdb.go12 symbols
internal/httpx/client_test.go12 symbols
internal/app/endpoint/v1/example.go12 symbols
internal/gokit/http/http.go11 symbols
internal/auth/jwt.go10 symbols
internal/observability/logger/logger_test.go9 symbols
internal/httpx/client.go9 symbols

Datastores touched

testdbDatabase · 1 repos
(mongodb)Database · 1 repos
appdbDatabase · 1 repos

For agents

$ claude mcp add go-service-starter-kit \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page