Skip to content

Configuration ​

config.LoadEnv() reads .env from the process working directory. An explicit filename is supported; a missing implicit .env is allowed, while a missing explicit file or invalid file returns an error. Process variables override file values, including empty values; unset values use defaults. The loader does not modify process environment variables.

VariableDefaultUse
ENVdevelopmentCLI/environment selection
PORT8080API listener
DATABASE_URLemptyRequired PostgreSQL URL; API startup pings it
RABBITMQ_URLamqp://guest:guest@localhost:5672/API connects before serving
JWT_SECRETemptyRequired signing secret of at least 32 bytes
JWT_EXPIRATION_HOURS24Integer, 1–24 hours validated by identity
REFRESH_TOKEN_EXPIRATION_DAYS7Integer, 1–365 days validated by identity
REDIS_HOSTlocalhostFuture Redis initialization
REDIS_PORT6379Future Redis initialization
REDIS_PASSWORDemptyFuture Redis initialization
CORS_ORIGINS*Request middleware's comma-separated origin configuration

CORS configuration is read separately by middleware, not stored in config.Env. Redis values exist in configuration and Compose, but the current API startup does not require a live Redis connection.

The legacy GetEnv helpers fall back for empty values and invalid conversions. That differs from LoadEnv's precedence and error behavior; application startup uses LoadEnv. See the config package.

go
package config_test

import (
	"fmt"
	"os"

	"github.com/prescriptoo/prescriptoo-api/pkg/config"
)

// LoadEnv accepts an explicit file, so tools can choose configuration without
// depending on the process working directory. Environment values take priority.
func ExampleLoadEnv() {
	// Fix values used by this example, restoring the caller's environment after it.
	for key, value := range map[string]string{
		"PORT": "9090", "JWT_EXPIRATION_HOURS": "1", "REFRESH_TOKEN_EXPIRATION_DAYS": "7",
	} {
		previous, exists := os.LookupEnv(key)
		defer func() {
			if exists {
				_ = os.Setenv(key, previous)
			} else {
				_ = os.Unsetenv(key)
			}
		}()
		if err := os.Setenv(key, value); err != nil {
			panic(err)
		}
	}
	file, err := os.CreateTemp("", "prescriptoo-config-*.env")
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := os.Remove(file.Name()); err != nil {
			panic(err)
		}
	}()
	if _, err := file.WriteString("DATABASE_URL=postgres://localhost/example\nPORT=8088\n"); err != nil {
		panic(err)
	}
	if err := file.Close(); err != nil {
		panic(err)
	}
	env, err := config.LoadEnv(file.Name())
	if err != nil {
		panic(err)
	}
	fmt.Println("Port:", env.Port)
	fmt.Println("Access lifetime:", env.JWTExpirationHours)
	// Output:
	// Port: 9090
	// Access lifetime: 1
}

Documentation follows the source. Planned contracts are marked explicitly.