Skip to content

Latest commit

Β 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

configfx

Typed config and secrets loader for Go services using Uber FX.

Replaces manual os.Getenv calls and raw Vault HTTP requests with struct-tag-driven, FX-native config/secrets injection.


Install

go get github.com/dehwyy/configfx

Vault subpackage:

go get github.com/dehwyy/configfx/vault

Usage

1. Define your structs

// internal/config/config.go
package config

type Config struct {
    AppEnv       string   `env:"APP_ENV,default=local"`
    AuthURL      string   `env:"AUTH_URL,required"`
    OtelEndpoint string   `env:"OTEL_ENDPOINT,default=localhost:4317"`
    CORSOrigins  []string `env:"CORS_ORIGINS,default=https://example.com"`
}

func (c *Config) IsLocal() bool { return c.AppEnv == "local" }

// internal/config/secrets.go
type Secrets struct {
    PgConnFmt   string `vault:"kv.shared.pg.conn.dev"`
    NatsServers string `vault:"kv.shared.nats.dev.servers"`
    NatsSeedKey string `vault:"kv.shared.nats.seedKey"`
}

2. Register as FX modules

func main() {
    fx.New(
        configfx.FxModule[config.Config](),
        cfgvault.FxModule[config.Secrets](
            os.Getenv("KEY_VAULT_ADDRESS"),
            os.Getenv("KEY_VAULT_TOKEN"),
        ),
        // both *config.Config and *config.Secrets are now in the DI container
        fx.Provide(func(cfg *config.Config, sec *config.Secrets) (*nats.Conn, error) {
            // ...
        }),
    ).Run()
}

3. Inject as dependencies

type Opts struct {
    fx.In
    Config  *config.Config
    Secrets *config.Secrets
}

func New(opts Opts) *Service { ... }

Struct tag reference

env tag (Config)

env:"KEY"                   // read APP_KEY, zero value if not set
env:"KEY,default=VALUE"     // use VALUE if not set
env:"KEY,required"          // error if not set and no default

Supported field types: string, int, bool, []string (comma-separated).

vault tag (Secrets)

vault:"mount.path.field"
  • mount β€” KV v1 mount name (e.g. kv)
  • path β€” secret path within mount (e.g. shared)
  • field β€” field name inside the secret map (e.g. pg.conn.dev)

Tag vault:"kv.shared.pg.conn.dev" β†’ reads GET /v1/kv/shared, takes data["pg.conn.dev"].

Batch reads: all fields from the same (mount, path) share one HTTP request.


Low-level API

If you need to load outside FX (e.g. early init, tests):

cfg, err := configfx.Load[config.Config]()

sec, err := vault.Load[config.Secrets](vaultAddr, vaultToken)

Pre-flight check CLI

The check subpackage provides a diagnostic binary that validates both env vars and Vault keys before service start.

// cmd/check/main.go
package main

import (
    "os"
    "git.example.com/myservice/internal/config"
    "github.com/dehwyy/configfx/check"
)

func main() {
    check.Run[config.Config, config.Secrets](
        os.Getenv("KEY_VAULT_ADDRESS"),
        os.Getenv("KEY_VAULT_TOKEN"),
    )
}

Output example:

Config validation (env vars):
  βœ“ APP_ENV              = "local"
  βœ“ AUTH_URL             = "https://auth.example.com/api/v1"
  βœ— REQUIRED_KEY         missing required env var

Secrets validation (Vault kv://https://vault.example.com):
  βœ“ kv.shared.pg.conn.dev                     β†’ PgConnFmt
  βœ— kv.shared.nats.dev.servers                failed to read kv/shared: ...

1 error(s) found. Fix before starting the service.

Exits 0 on success, 1 on any error.


Project structure

configfx/
β”œβ”€β”€ loader.go          # Load[T]() β€” env vars β†’ struct
β”œβ”€β”€ validate.go        # Validate[T]() β€” dry-run, no side effects
β”œβ”€β”€ fx.go              # FxModule[T]() β€” wraps Load in fx.Provide
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ env/           # tag parser + type coercion
β”‚   └── field/         # reflect-based field setter
β”œβ”€β”€ vault/
β”‚   β”œβ”€β”€ loader.go      # Load[T](addr, token) β€” Vault KV v1 β†’ struct
β”‚   β”œβ”€β”€ validate.go    # Validate[T](addr, token) β€” dry-run
β”‚   β”œβ”€β”€ fx.go          # FxModule[T](addr, token) β€” wraps Load in fx.Provide
β”‚   └── internal/      # vault tag parser
└── check/
    └── check.go       # Run[C, S](addr, token) β€” CLI validator

Requirements

  • Go 1.25.5+
  • Vault KV v1 (not KV v2)

About

πŸŒ™ Typed Config & Secrets loader with Generics & UberFX

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages