A starter setup for a production Gin app, including: TLS & HTTP/3 ready (just add certs!), structured logging, Prometheus HTTP metrics, and Kubernetes health probes.
First, clone the project.
New HTTP route handlers and middleware can be added to the controllers/ and
middleware/ directories respectively.
See Gin Docs - Examples for a guide
on how to implement these and some of the features Gin offers.
main.go is the main entrypoint, so functionality is attached to the server here.
.
├── .ko.yaml # Ko build config
├── controllers/ # HTTP route handlers
│ └── health.go
├── Dockerfile # Docker build config
├── go.mod
├── go.sum
├── main.go # Project entrypoint; sets up and runs Gin server
├── middleware/ # Gin middleware for logging, metrics, etc.
│ ├── errors.go
│ ├── logging.go
│ ├── metrics.go
│ └── security.go
└── README.mdAll container builds use Chainguard's Static Base Image for security.
go build . -o gin
To build with Ko, pushing to the local Docker image store
tagged as gin:latest.
export KO_DOCKER_REPO=gin
ko build --bare --local .Configure Ko build in the .ko.yaml file.
docker build . -t gin:latest| Variable | Default | Description |
|---|---|---|
| PORT | 8080 |
The port to serve the application on. |
| GIN_MODE | release |
Mode to start the Gin server in, available options: release, debug, test. |
| GIN_TLS_CERT_FILE | Path to a PEM-encoded TLS certificate file, with the CA chain concatenated if there is one. Leave unset to disable HTTPS. | |
| GIN_TLS_KEY_FILE | Path to a PEM-encoded TLS key file. Leave unset to disable HTTPS. | |
| GIN_HTTP3_ENABLED | true |
By default, running the application with TLS starts a listener for QUIC connections alongside the standard TCP one. Set to false to disable the extra listener. |
| Path | Description |
|---|---|
/healthz |
Kubernetes liveness probe; simply returns a 200 OK response |
/readyz |
Kubernetes readiness probe; by default, returns a 200 OK response, and should be configured to include app readiness checks. |
/metrics |
Prometheus metrics endpoint. Returns application metrics in Prometheus format. |
All logging is done to STDOUT in a structured manner using the Go slog library.
HTTP requests are logged with the following fields:
| Field | Type | Description | Example |
|---|---|---|---|
time |
string | Timestamp in RFC 3339 format. | 2025-11-29T18:01:38.300Z |
level |
int | Log severity level. | WARN |
msg |
string | HTTP response code and its meaning. | HTTP 503 (Service Unavailable) |
status |
int | HTTP response code. | 200 |
method |
string | HTTP request method. | GET |
path |
string | Request route. | /healthz |
client_ip |
string | Client IP address. | 127.0.0.1 |
duration |
string | Time taken for the request to complete. | 107.747µs |
error |
string | The error message, if there was one. | "Error #01: MQTT broker not connected\n" |
Prometheus metrics are recorded using the default registry.
| Name | Type | Labels | Description |
|---|---|---|---|
http_requests_total |
Counter | method, route, status | Total number of HTTP requests. |
http_request_duration_seconds |
Histogram | method, route, status | HTTP request duration in seconds. |
http_in_flight_requests |
Gauge | Number of requests currently being handled by the service. |
// create new registry
reg := prometheus.NewRegistry()
// pass the registerer to the middleware
r.Use(middleware.PrometheusMetrics(reg))
// attach the registry to the metrics endpoint
r.GET("/metrics", gin.WrapH(promhttp.HandlerFor(reg, promhttp.HandlerOpts{})))- Jack Luke