.env.go.local

In professional Go development, you often want a hierarchy: System Env Vars > Local File > Default Values.

Here is a production-ready setup using the godotenv library with overrides:

package main

import ( "log" "os" "path/filepath"

"github.com/joho/godotenv"

)

func LoadEnv() // Get the current working directory execPath, err := os.Getwd() if err != nil log.Fatal(err)

// Define the path to your local file
envPath := filepath.Join(execPath, ".env.go.local")
// Load the file.
// Note: If the file doesn't exist, godotenv.Load returns an error.
// We usually want to ignore this error in Production environments.
if _, err := os.Stat(envPath); err == nil 
	if err := godotenv.Load(envPath); err != nil 
		log.Printf("Error loading .env.go.local file: %v", err)
	 else 
		log.Println("Loaded environment from .env.go.local")

func main() LoadEnv()

// Use the variable
apiKey := os.Getenv("STRIPE_API_KEY")
// ...

You run go run main.go and wonder why your local overrides aren’t working. The solution: alias go run -tags local in your shell.

While .env.go.local is a pattern, not a library, you see echoes of it in major projects:

package config

import ( "log" "os" "github.com/joho/godotenv" )

func Load() // Load default .env first (if it exists) if err := godotenv.Load(".env"); err != nil log.Println("No .env file found, using system envs")

// Override with .env.go.local – fails silently if not present
_ = godotenv.Overload(".env.go.local")

func Get(key, defaultValue string) string if val := os.Getenv(key); val != "" return val return defaultValue

At its core, .env.go.local is a naming convention—a hybrid between a configuration file and a Go source file. Unlike standard .env files which are parsed at runtime, .env.go.local is typically a Go package that exports variables, or a structured file that is read into your main.go exclusively during development. .env.go.local

A typical .env.go.local might look like this:

// env/env.local.go
//go:build local
// +build local

package env

func init() os.Setenv("DB_HOST", "localhost:5432") os.Setenv("API_KEY", "dev-12345") os.Setenv("LOG_LEVEL", "debug")

var Config = struct Port string Port: "8080",

By using build tags (//go:build local), this file is only compiled when you explicitly tell Go to use the local tag. In production, it is completely ignored.

Instead of init(), use a local config loader:

// config/env.go.local
package config

func LocalOverrides() os.Setenv("PORT", "3000") In professional Go development, you often want a

Then in your main.go:

func main() 
    if os.Getenv("GO_ENV") == "local" 
        config.LocalOverrides()
// ... rest of app

This is safer because you control when overrides apply.

One of the hidden benefits is test isolation. Create config/env_test.go.local:

//go:build local_test

package config

func init() os.Setenv("TEST_MODE", "true") os.Setenv("DB_HOST", "localhost:5432")

Run tests with:

go test -tags local_test ./...