starterA

module
v0.0.0-...-3674af8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: MIT

README

Go Application Starter

A Go HTTP starter built with Chi, Turso/libSQL, sqlc, and Gomponents. It includes server configuration, health checks, metrics, and graceful shutdown, with no sample domain model or CRUD endpoints.

Included

  • Chi routing and middleware
  • Local file databases and remote Turso databases through the libSQL database layer
  • sqlc configuration ready for application queries
  • Gomponents HTML rendering
  • Authentication middleware and a development mock provider for future protected routes
  • Request timeouts and size limits, explicit CORS headers, per-client rate limiting, and HTTPS 1.2 or newer
  • Liveness/readiness probes, Prometheus metrics, and optional OTLP tracing
  • CI, a multi-stage Docker image, and common Make targets

Requirements

  • Go 1.26.5 or newer
  • sqlc only when regenerating database code
  • Docker only when building or running the container image

Quick Start

The example configuration uses a local file:starter-a.db database. The embedded schema migrations run automatically during application startup.

cp cmd/config.toml config.toml
go run ./cmd

The application listens on http://localhost:8080. The same startup can be run with the Makefile without copying the config:

make run

Enable debug logging with -v, or select another configuration file with -c:

go run ./cmd -v -c path/to/config.toml

Configuration

The included cmd/config.toml contains runnable local defaults:

[Server]
Port = "8080"
EnableHTTPS = false
HTTPSPort = "443"
AllowedCorsURLs = ["http://localhost:3000"]
TaskTimeOutInSeconds = 30
ReadTimeoutInSeconds = 15
WriteTimeoutInSeconds = 35
IdleTimeoutInSeconds = 60
RateLimitRequestsPerSecond = 20
RateLimitBurst = 40
ServerDomain = ""

[App]
Environment = "dev"

[Log]
Format = "auto"
Level = "info"
GCPProjectID = ""

[Database]
TursoConnectionString = "file:starter-a.db"

To use Turso, set the connection string through the environment so the token does not need to be committed:

export TURSO_CONNECTION_STRING='libsql://database-name.turso.io?authToken=token'
go run ./cmd -c cmd/config.toml

Environment variables take precedence over the file. Supported overrides are:

TOML setting Environment variable
App.Environment ENVIRONMENT
Server.Port SERVER_PORT
Server.EnableHTTPS ENABLE_HTTPS
Server.HTTPSPort HTTPS_SERVER_PORT
Server.AllowedCorsURLs ALLOWED_CORS_URLS
Server.TaskTimeOutInSeconds TASK_TIMEOUT_IN_SECONDS
Server.ReadTimeoutInSeconds READ_TIMEOUT_IN_SECONDS
Server.WriteTimeoutInSeconds WRITE_TIMEOUT_IN_SECONDS
Server.IdleTimeoutInSeconds IDLE_TIMEOUT_IN_SECONDS
Server.RateLimitRequestsPerSecond RATE_LIMIT_REQUESTS_PER_SECOND
Server.RateLimitBurst RATE_LIMIT_BURST
Server.ServerDomain SERVER_DOMAIN
Database.TursoConnectionString TURSO_CONNECTION_STRING
Log.Format LOG_FORMAT
Log.Level LOG_LEVEL
Log.GCPProjectID GOOGLE_CLOUD_PROJECT

Local SQLite uses one pooled connection, so concurrent requests queue rather than compete for the database write lock. Each connection also waits up to five seconds for locks held by another process. Override this wait in milliseconds with file:starter-a.db?_busy_timeout=10000. Existing SQLite URL options are preserved. Remote Turso retains a pool of up to 25 connections.

Keep transactions short. While holding a transaction, execute its queries through that transaction rather than the database pool; the single local connection remains occupied until commit or rollback. Sustained lock contention can still return an error after the wait expires.

When HTTPS is enabled, ServerDomain is required and must resolve to the server. The HTTP and HTTPS listeners are both shut down gracefully, and the ACME certificate cache is written under certs/.

Authentication and Routes

The home page and operational endpoints are public. No application API routes are included. Authentication middleware remains in internal/auth/ for future protected routes; its mock provider is for development only. Use a production implementation of auth.Servicer when adding authentication, and add CSRF protection for cookie-authenticated write routes.

Method Path Authentication Description
GET / No Render the home page
GET /healthz No Process liveness
GET /readyz No Database readiness
GET /metrics No Prometheus-compatible metrics

Logging

Logs go to stderr through log/slog. Log.Format chooses the encoding:

Format Behavior
auto (default) Text when started with go run or when stderr is a terminal; JSON otherwise
text Human-readable key=value lines
json One JSON object per line using Cloud Logging field names (severity, message, time)

The go run check looks at whether the executable lives in a go-build cache directory, so a deployed binary in a container gets JSON without any flags. --verbose forces debug level regardless of Log.Level. When Log.GCPProjectID (or GOOGLE_CLOUD_PROJECT) is set, request logs include the logging.googleapis.com/trace fields so Cloud Run log lines link to Cloud Trace.

Operations and Observability

User-facing routes use a per-client in-memory token bucket. Health, readiness, and metrics remain available during traffic spikes. Behind a reverse proxy, rate-limit at the edge or change the client-key logic to trust only that proxy's forwarding headers.

Prometheus can scrape /metrics. Nonstandard HTTP methods share the OTHER label, keeping request counter and duration metric categories bounded. Restrict it at the network or reverse-proxy layer if operational data should not be public.

OTLP/HTTP trace export is disabled by default. Enable it with standard OpenTelemetry environment variables:

export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

The application samples 10% of new root traces while preserving parent sampling decisions. Request logs include trace and span IDs when available.

Development

make test       # go test ./...
make vet        # go vet ./...
make build      # bin/starter-a
make generate   # sqlc generate
make docker-build

Add numbered .sql migrations to internal/database/schema/ and sqlc queries to internal/database/queries/. Then run make generate and commit the generated internal/database/repo/ files. Until queries are added, make generate is a no-op. A fresh database contains only migration bookkeeping; existing database tables are left intact.

cmd/main.go loads configuration, initializes shared resources, and runs the web server. Add domain services and repository wiring as your application needs them.

  • internal/app/ assembles shared dependencies and owns their lifecycle.
  • internal/server/ builds the HTTP middleware chain and owns server lifecycle.
  • internal/logging/ builds the logger and selects text or JSON output.
  • internal/handlers/http/ adapts HTTP requests and responses.
  • internal/routes/ maps endpoints and applies route-level middleware.
  • internal/database/ owns connections and embedded migrations, with directories ready for application schema and sqlc queries.
  • internal/auth/ contains the auth contract, middleware, and mock provider.
  • internal/ui/ contains Gomponents views.

Docker

docker build -t starter-a .
docker run --rm -p 8080:8080 -v starter-a-data:/data starter-a

The image runs as an unprivileged user and stores the default local database in the /data volume.

License

This project is available under the MIT License.

Directories

Path Synopsis
internal
app
auth
Package auth provides optional, provider-agnostic authentication scaffolding.
Package auth provides optional, provider-agnostic authentication scaffolding.
logging
Package logging builds the application's slog.Logger and decides between human-readable text output for terminals and structured JSON for log collectors such as Cloud Logging.
Package logging builds the application's slog.Logger and decides between human-readable text output for terminals and structured JSON for log collectors such as Cloud Logging.
server
Package server assembles the web application's HTTP handler chain and owns the lifecycle of the listening servers.
Package server assembles the web application's HTTP handler chain and owns the lifecycle of the listening servers.
ui

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL