Forge
1.x
Docs/Forge/Struct Binding
Open

Reading5 min
Updated31 Jul 2026
Sourcev1/confy/struct-binding.mdx

Confy can map configuration sections directly into Go structs using reflection. This provides compile-time type safety and a clean way to group related configuration.

Basic Binding01

Use Bind to map a configuration section to a struct:

type DatabaseConfig struct {
    Host     string `yaml:"host"`
    Port     int    `yaml:"port"`
    Name     string `yaml:"name"`
    SSLMode  string `yaml:"ssl_mode"`
}

var dbCfg DatabaseConfig
err := cfg.Bind("database", &dbCfg)
if err != nil {
    log.Fatal(err)
}

fmt.Println(dbCfg.Host) // "localhost"
fmt.Println(dbCfg.Port) // 5432

Given this config file:

database:
  host: localhost
  port: 5432
  name: mydb
  ssl_mode: disable

Default Tags02

Use the default struct tag to provide default values when a key is missing from the config:

type ServerConfig struct {
    Host            string        `yaml:"host" default:"0.0.0.0"`
    Port            int           `yaml:"port" default:"8080"`
    ReadTimeout     time.Duration `yaml:"read_timeout" default:"30s"`
    WriteTimeout    time.Duration `yaml:"write_timeout" default:"60s"`
    MaxHeaderBytes  int           `yaml:"max_header_bytes" default:"1048576"`
    ShutdownTimeout time.Duration `yaml:"shutdown_timeout" default:"15s"`
}

var serverCfg ServerConfig
cfg.Bind("server", &serverCfg)

// If server.port is missing from config, serverCfg.Port == 8080

Supported Default Types

Go TypeDefault ExampleNotes
stringdefault:"hello"Direct string value
int, int64default:"42"Parsed from string
float64default:"3.14"Parsed from string
booldefault:"true""true", "yes", "1"
time.Durationdefault:"30s"Go duration syntax
[]stringdefault:"a,b,c"Comma-separated

Binding with Defaults03

BindWithDefault provides a fallback struct if the section is entirely missing:

defaultDB := DatabaseConfig{
    Host: "localhost",
    Port: 5432,
    Name: "defaultdb",
}

var dbCfg DatabaseConfig
cfg.BindWithDefault("database", &dbCfg, defaultDB)

Binding with Options04

BindWithOptions provides fine-grained control over the binding process:

var dbCfg DatabaseConfig
err := cfg.BindWithOptions("database", &dbCfg, confy.BindOptions{
    IgnoreUnknownKeys: true,
    Strict:            false,
})

Nested Structs05

Nested structs map to nested configuration sections:

type AppConfig struct {
    Server struct {
        Host string `yaml:"host" default:"localhost"`
        Port int    `yaml:"port" default:"8080"`
    } `yaml:"server"`

    Database struct {
        Host     string `yaml:"host"`
        Port     int    `yaml:"port" default:"5432"`
        Name     string `yaml:"name"`
        Pool     struct {
            MaxOpen int           `yaml:"max_open" default:"25"`
            MaxIdle int           `yaml:"max_idle" default:"5"`
            MaxLife time.Duration `yaml:"max_life" default:"5m"`
        } `yaml:"pool"`
    } `yaml:"database"`

    Logging struct {
        Level  string `yaml:"level" default:"info"`
        Format string `yaml:"format" default:"json"`
    } `yaml:"logging"`
}

var appCfg AppConfig
cfg.Bind("", &appCfg) // empty prefix binds to root
server:
  host: 0.0.0.0
  port: 3000

database:
  host: postgres.internal
  port: 5432
  name: production
  pool:
    max_open: 50

logging:
  level: warn

Sub-Configurations06

Use Sub to create a scoped view of a configuration section:

// Create a sub-configuration for the database section
dbConfig := cfg.Sub("database")

host := dbConfig.GetString("host")  // no "database." prefix needed
port := dbConfig.GetInt("port", 5432)

// Bind from the sub-configuration
var poolCfg PoolConfig
dbConfig.Bind("pool", &poolCfg)

Struct Tags07

Confy recognizes the following struct tags:

TagPurposeExample
yamlField name mappingyaml:"host"
jsonFallback field namejson:"host"
defaultDefault valuedefault:"8080"
mapstructureAlternative mappingmapstructure:"host"
Note

The yaml tag takes precedence. If no tag is provided, the field name is lowercased and used as the key.

Production Pattern08

A common pattern is to define all config in a single struct and bind at startup:

type Config struct {
    App struct {
        Name    string `yaml:"name" default:"myapp"`
        Version string `yaml:"version"`
        Debug   bool   `yaml:"debug" default:"false"`
    } `yaml:"app"`

    Server struct {
        Host string `yaml:"host" default:"0.0.0.0"`
        Port int    `yaml:"port" default:"8080"`
    } `yaml:"server"`

    Database struct {
        DSN string `yaml:"dsn"`
    } `yaml:"database"`
}

func LoadConfig() (*Config, error) {
    c, err := confy.AutoLoadConfy("myapp", nil)
    if err != nil {
        return nil, err
    }

    var config Config
    if err := c.Bind("", &config); err != nil {
        return nil, err
    }

    return &config, nil
}