---
title: "GN007 – Set gin.ReleaseMode in Production"
impact: medium
impactDescription: "The default gin.DebugMode prints every registered route and request detail to stdout, leaking your API surface and increasing log noise in production."
tags: [go, gin, security, configuration]
---

# GN007 – Set `gin.ReleaseMode` in Production

## Rule

Set `gin.SetMode(gin.ReleaseMode)` before calling `gin.New()` or `gin.Default()` in production builds. Read the mode from an environment variable so it can differ between environments.

## Why

Debug mode outputs all routes on startup and logs detailed request info. In production this:
- Leaks your API surface to anyone with log access.
- Adds unnecessary CPU cost for string formatting.
- Makes it harder to find meaningful log entries.

## Wrong

```go
// main.go — mode not set, defaults to DebugMode
func main() {
    r := gin.Default()          // ❌ runs in debug mode, dumps all routes to stdout
    r.GET("/internal/admin", adminHandler)  // ❌ exposed in startup log
    r.Run(":8080")
}

// Hardcoded mode
gin.SetMode(gin.DebugMode)     // ❌ always debug, regardless of environment
```

## Correct

```go
func main() {
    // Read from environment — "release", "debug", or "test"
    ginMode := os.Getenv("GIN_MODE")
    if ginMode == "" {
        ginMode = gin.ReleaseMode  // safe default
    }
    gin.SetMode(ginMode)

    r := gin.New()
    r.Use(gin.Recovery())   // see GN009 for Recovery middleware
    // ... register routes
    r.Run(":" + os.Getenv("PORT"))
}
```

Or rely on Gin's built-in env var support: Gin automatically reads `GIN_MODE` — set it to `release` in your container/systemd environment and `gin.SetMode` is not even needed explicitly.

```bash
# Production container / systemd
GIN_MODE=release
```

## Notes

- `gin.Default()` adds `gin.Logger()` and `gin.Recovery()` automatically in debug mode — in production, use `gin.New()` and add your structured logger and Recovery explicitly (see GN009).
- Never call `gin.SetMode` after `gin.New()` — the mode must be set before the engine is created.
- In tests, set `gin.SetMode(gin.TestMode)` in `TestMain` to silence route debug output.
