confkit

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 14 Imported by: 0

README

confkit

CI Go Reference

Typed, validated, secret-safe configuration contracts for Go services.

confkit turns scattered os.Getenv calls into one startup contract:

  • load typed structs
  • validate before the service starts
  • redact secrets in errors and generated output
  • generate .env.example and Markdown docs from the same source

It is not trying to replace Viper or Koanf as a full configuration system. It is for teams that want an env-first contract: define what your service needs, validate it at startup, and keep docs/examples in sync with code.

package main

import (
	"log"

	conf "github.com/ahmertsengol/confkit"
)

type Config struct {
	Port        int    `conf:"PORT"`
	DatabaseURL string `conf:"DATABASE_URL"`
	JWTSecret   string `conf:"JWT_SECRET"`
	Env         string `conf:"ENV"`
}

func main() {
	cfg, err := conf.Load[Config](conf.Contract(
		conf.Int("PORT").Default(8080).Min(1).Max(65535).Description("HTTP server port"),
		conf.String("DATABASE_URL").Required().URL().Description("Primary database connection URL"),
		conf.String("JWT_SECRET").Required().Min(32).Secret().Description("JWT signing secret"),
		conf.Enum("ENV", "development", "staging", "production").Default("development"),
	), conf.WithDotEnv(".env"))
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("starting %s service on port %d", cfg.Env, cfg.Port)
}

Why

Broken configuration usually appears late: during deploy, after boot, or inside a request path. confkit moves those failures to startup and makes the fix obvious.

Invalid configuration:

DATABASE_URL
  Required environment variable is missing.

PORT
  Expected integer, got "abc".

JWT_SECRET
  Must be at least 32 characters. Current value: [REDACTED].

What makes it different

Need Typical tool confkit's focus
Many config backends and formats Viper / Koanf Keep using those when you need them
Struct tags from env envconfig / caarlos0/env Simpler for basic env loading
Dotenv loading godotenv Good for loading .env into the process
Startup config contract confkit Validate, type, redact, and document service config

Use confkit when you want your configuration to behave like a small schema: required keys, defaults, validation rules, secret redaction, and generated docs.

Install

go get github.com/ahmertsengol/confkit

Simple env loading

For small programs, use struct tags directly:

type Config struct {
	Port        int    `conf:"PORT"`
	ServiceName string // SERVICE_NAME
	Debug       bool   `conf:"DEBUG"`
}

cfg, err := conf.LoadEnv[Config]()

If a field does not have a conf tag, confkit maps the field name to screaming snake case.

Sources and precedence

Load uses deterministic precedence:

defaults < dotenv files < process environment < explicit sources

Explicit sources are useful in tests:

cfg, err := conf.Load[Config](
	contract,
	conf.WithSource(conf.MapSource(map[string]string{
		"PORT": "3000",
	})),
)

WithDotEnv(".env") ignores a missing file, which keeps production deployments from depending on local development files. Use WithRequiredDotEnv(path) when a file must exist.

Generate .env.example

contract := conf.Contract(
	conf.Int("PORT").Default(8080).Description("HTTP server port"),
	conf.String("DATABASE_URL").Required().URL().Description("Primary database connection URL"),
	conf.String("JWT_SECRET").Required().Secret().Description("JWT signing secret"),
)

_ = conf.WriteExample(contract, os.Stdout)

Output:

# HTTP server port
PORT=8080

# Primary database connection URL
DATABASE_URL=

# JWT signing secret
JWT_SECRET=

Generate Markdown docs

_ = conf.WriteMarkdown(contract, os.Stdout)
| Key | Type | Required | Default | Secret | Description |
|---|---|---|---|---|---|
| PORT | int | no | 8080 | no | HTTP server port |

Supported fields

  • String
  • Int
  • Float
  • Bool
  • Duration
  • Enum
  • List

Common modifiers:

  • Required
  • Optional
  • Default
  • Secret
  • Desc

Common validators:

  • Min
  • Max
  • Regex
  • URL
  • Email
  • Hostname
  • IP
  • NonEmpty
  • enum membership through Enum

Safety defaults

  • Missing .env files are ignored by WithDotEnv.
  • Use WithRequiredDotEnv for strict file loading.
  • Invalid contracts return aggregate errors instead of panicking.
  • Duplicate contract keys and duplicate struct mappings are rejected.
  • Secret fields are redacted in errors and generated defaults.

Project status

confkit is library-first. Remote providers, hot reload, Vault, Consul, and Kubernetes integrations are intentionally outside the first release surface.

Documentation

Overview

Package confkit validates, types, redacts, and documents Go service configuration at startup.

Define a configuration contract once, then use it to load typed structs, format actionable errors, and generate .env.example or Markdown docs.

Index

Examples

Constants

View Source
const (
	CodeRequired        = "required"
	CodeInvalidType     = "invalid_type"
	CodeMin             = "min"
	CodeMax             = "max"
	CodeRegex           = "regex"
	CodeInvalidURL      = "invalid_url"
	CodeInvalidEnum     = "invalid_enum"
	CodeInvalidEmail    = "invalid_email"
	CodeInvalidHost     = "invalid_hostname"
	CodeInvalidIP       = "invalid_ip"
	CodeNonEmpty        = "non_empty"
	CodeInvalidRegex    = "invalid_regex"
	CodeInvalidContract = "invalid_contract"
	CodeDuplicateKey    = "duplicate_key"
	CodeUnknown         = "unknown_field"
)

Variables

This section is empty.

Functions

func Load

func Load[T any](contract *ConfigContract, opts ...Option) (T, error)

Load reads configuration values from sources, validates them with the contract, and assigns the typed result into T.

Example
package main

import (
	"fmt"

	conf "github.com/ahmertsengol/confkit"
)

func main() {
	type Config struct {
		Port        int    `conf:"PORT"`
		DatabaseURL string `conf:"DATABASE_URL"`
		Env         string `conf:"ENV"`
	}

	cfg, err := conf.Load[Config](
		conf.Contract(
			conf.Int("PORT").Default(8080).Min(1).Max(65535),
			conf.String("DATABASE_URL").Required().URL(),
			conf.Enum("ENV", "development", "staging", "production").Default("development"),
		),
		conf.WithSource(conf.MapSource(map[string]string{
			"DATABASE_URL": "https://db.example.com/app",
		})),
	)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("%d %s %s\n", cfg.Port, cfg.DatabaseURL, cfg.Env)
}
Output:
8080 https://db.example.com/app development

func LoadEnv

func LoadEnv[T any]() (T, error)

LoadEnv loads a struct directly from the process environment using conf tags and field types. Missing values leave the field's zero value unchanged.

func WriteExample

func WriteExample(contract *ConfigContract, writer io.Writer) error

WriteExample writes a deterministic .env.example from contract metadata.

Example
package main

import (
	"os"

	conf "github.com/ahmertsengol/confkit"
)

func main() {
	contract := conf.Contract(
		conf.Int("PORT").Default(8080).Desc("HTTP server port"),
		conf.String("DATABASE_URL").Required().URL().Desc("Primary database connection URL"),
	)

	_ = conf.WriteExample(contract, os.Stdout)
}
Output:
# HTTP server port
PORT=8080

# Primary database connection URL
DATABASE_URL=

func WriteMarkdown

func WriteMarkdown(contract *ConfigContract, writer io.Writer) error

WriteMarkdown writes a Markdown table documenting the contract.

Types

type BoolField

type BoolField struct {
	// contains filtered or unexported fields
}

BoolField validates boolean configuration values.

func Bool

func Bool(key string) *BoolField

Bool creates a boolean field.

func (*BoolField) Default

func (f *BoolField) Default(value bool) *BoolField

func (*BoolField) Desc

func (f *BoolField) Desc(description string) *BoolField

func (*BoolField) Description

func (f *BoolField) Description(description string) *BoolField

func (*BoolField) Optional

func (f *BoolField) Optional() *BoolField

func (*BoolField) Required

func (f *BoolField) Required() *BoolField

func (*BoolField) Secret

func (f *BoolField) Secret() *BoolField

type ConfigContract

type ConfigContract struct {
	// contains filtered or unexported fields
}

ConfigContract describes the configuration keys, parsers, validation rules, and documentation metadata used by Load.

func Contract

func Contract(fields ...Field) *ConfigContract

Contract creates a configuration contract from field builders.

type DurationField

type DurationField struct {
	// contains filtered or unexported fields
}

DurationField validates time.Duration configuration values.

func Duration

func Duration(key string) *DurationField

Duration creates a time.Duration field parsed with time.ParseDuration.

func (*DurationField) Default

func (f *DurationField) Default(value time.Duration) *DurationField

func (*DurationField) Desc

func (f *DurationField) Desc(description string) *DurationField

func (*DurationField) Description

func (f *DurationField) Description(description string) *DurationField

func (*DurationField) Max

func (*DurationField) Min

func (*DurationField) Optional

func (f *DurationField) Optional() *DurationField

func (*DurationField) Required

func (f *DurationField) Required() *DurationField

func (*DurationField) Secret

func (f *DurationField) Secret() *DurationField

type EnumField

type EnumField struct {
	// contains filtered or unexported fields
}

EnumField validates a string against a fixed set of values.

func Enum

func Enum(key string, values ...string) *EnumField

Enum creates an enum field.

func (*EnumField) Default

func (f *EnumField) Default(value string) *EnumField

func (*EnumField) Desc

func (f *EnumField) Desc(description string) *EnumField

func (*EnumField) Description

func (f *EnumField) Description(description string) *EnumField

func (*EnumField) Optional

func (f *EnumField) Optional() *EnumField

func (*EnumField) Required

func (f *EnumField) Required() *EnumField

func (*EnumField) Secret

func (f *EnumField) Secret() *EnumField

type Error

type Error struct {
	Issues []Issue
}

Error aggregates all configuration issues found in a load attempt.

func (*Error) Error

func (e *Error) Error() string

type Field

type Field interface {
	// contains filtered or unexported methods
}

Field is implemented by all configuration field builders.

type FloatField

type FloatField struct {
	// contains filtered or unexported fields
}

FloatField validates float64 configuration values.

func Float

func Float(key string) *FloatField

Float creates a float64 field.

func (*FloatField) Default

func (f *FloatField) Default(value float64) *FloatField

func (*FloatField) Desc

func (f *FloatField) Desc(description string) *FloatField

func (*FloatField) Description

func (f *FloatField) Description(description string) *FloatField

func (*FloatField) Max

func (f *FloatField) Max(max float64) *FloatField

func (*FloatField) Min

func (f *FloatField) Min(min float64) *FloatField

func (*FloatField) Optional

func (f *FloatField) Optional() *FloatField

func (*FloatField) Required

func (f *FloatField) Required() *FloatField

func (*FloatField) Secret

func (f *FloatField) Secret() *FloatField

type IntField

type IntField struct {
	// contains filtered or unexported fields
}

IntField validates integer configuration values.

func Int

func Int(key string) *IntField

Int creates an integer field.

func (*IntField) Default

func (f *IntField) Default(value int) *IntField

func (*IntField) Desc

func (f *IntField) Desc(description string) *IntField

func (*IntField) Description

func (f *IntField) Description(description string) *IntField

func (*IntField) Max

func (f *IntField) Max(max int) *IntField

func (*IntField) Min

func (f *IntField) Min(min int) *IntField

func (*IntField) Optional

func (f *IntField) Optional() *IntField

func (*IntField) Required

func (f *IntField) Required() *IntField

func (*IntField) Secret

func (f *IntField) Secret() *IntField

type Issue

type Issue struct {
	Key     string
	Code    string
	Message string
	Secret  bool
}

Issue describes one configuration problem.

type ListField

type ListField struct {
	// contains filtered or unexported fields
}

ListField validates comma-separated string lists.

func List

func List(key string) *ListField

List creates a comma-separated string list field.

func (*ListField) Default

func (f *ListField) Default(value []string) *ListField

func (*ListField) Desc

func (f *ListField) Desc(description string) *ListField

func (*ListField) Description

func (f *ListField) Description(description string) *ListField

func (*ListField) Max

func (f *ListField) Max(max int) *ListField

func (*ListField) Min

func (f *ListField) Min(min int) *ListField

func (*ListField) Optional

func (f *ListField) Optional() *ListField

func (*ListField) Required

func (f *ListField) Required() *ListField

func (*ListField) Secret

func (f *ListField) Secret() *ListField

func (*ListField) Separator

func (f *ListField) Separator(separator string) *ListField

type Option

type Option func(*options)

Option customizes Load.

func WithDotEnv

func WithDotEnv(path string) Option

WithDotEnv loads values from a dotenv file when it exists. Missing files are ignored so local .env files can be used in development without breaking production deployments.

func WithRequiredDotEnv

func WithRequiredDotEnv(path string) Option

WithRequiredDotEnv loads values from a dotenv file and returns an error when the file cannot be read.

func WithSource

func WithSource(source Source) Option

WithSource adds an explicit source. Explicit sources have higher precedence than .env files and the process environment.

type Source

type Source interface {
	Lookup(key string) (string, bool)
}

Source provides raw string values by configuration key.

func MapSource

func MapSource(values map[string]string) Source

MapSource creates an in-memory source for tests and explicit overrides.

type StringField

type StringField struct {
	// contains filtered or unexported fields
}

StringField validates string configuration values.

func String

func String(key string) *StringField

String creates a string field.

func (*StringField) Default

func (f *StringField) Default(value string) *StringField

func (*StringField) Desc

func (f *StringField) Desc(description string) *StringField

func (*StringField) Description

func (f *StringField) Description(description string) *StringField

func (*StringField) Email

func (f *StringField) Email() *StringField

func (*StringField) Hostname

func (f *StringField) Hostname() *StringField

func (*StringField) IP

func (f *StringField) IP() *StringField

func (*StringField) Max

func (f *StringField) Max(max int) *StringField

func (*StringField) Min

func (f *StringField) Min(min int) *StringField

func (*StringField) NonEmpty

func (f *StringField) NonEmpty() *StringField

func (*StringField) Optional

func (f *StringField) Optional() *StringField

func (*StringField) Regex

func (f *StringField) Regex(pattern string) *StringField

func (*StringField) Required

func (f *StringField) Required() *StringField

func (*StringField) Secret

func (f *StringField) Secret() *StringField

func (*StringField) URL

func (f *StringField) URL() *StringField

Directories

Path Synopsis
examples
basic command
http-server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL