Skip to main content
Kratos provides a flexible configuration system that supports multiple sources, hot-reloading, and environment-specific settings.

Configuration System Overview

Kratos configuration features:
  • Multiple sources (files, environment variables, remote config)
  • Hot-reloading with watchers
  • Format support (YAML, JSON, TOML, XML)
  • Configuration merging and overrides
  • Type-safe configuration binding

Basic Configuration

1
Define Configuration Structure
2
Create a configuration struct in internal/conf/:
3
package conf

type Bootstrap struct {
	Server   *Server   `json:"server"`
	Data     *Data     `json:"data"`
	Registry *Registry `json:"registry"`
}

type Server struct {
	HTTP *HTTP `json:"http"`
	GRPC *GRPC `json:"grpc"`
}

type HTTP struct {
	Network string `json:"network"`
	Addr    string `json:"addr"`
	Timeout string `json:"timeout"`
}

type GRPC struct {
	Network string `json:"network"`
	Addr    string `json:"addr"`
	Timeout string `json:"timeout"`
}

type Data struct {
	Database *Database `json:"database"`
	Redis    *Redis    `json:"redis"`
}

type Database struct {
	Driver string `json:"driver"`
	Source string `json:"source"`
}

type Redis struct {
	Addr         string `json:"addr"`
	ReadTimeout  string `json:"read_timeout"`
	WriteTimeout string `json:"write_timeout"`
}

type Registry struct {
	Consul *Consul `json:"consul"`
}

type Consul struct {
	Address string `json:"address"`
	Scheme  string `json:"scheme"`
}
4
Create Configuration File
5
Create a YAML configuration file:
6
server:
  http:
    network: tcp
    addr: 0.0.0.0:8000
    timeout: 1s
  grpc:
    network: tcp
    addr: 0.0.0.0:9000
    timeout: 1s

data:
  database:
    driver: mysql
    source: root:root@tcp(127.0.0.1:3306)/test?parseTime=True
  redis:
    addr: 127.0.0.1:6379
    read_timeout: 0.2s
    write_timeout: 0.2s

registry:
  consul:
    address: 127.0.0.1:8500
    scheme: http
7
Load Configuration
8
Load the configuration in your application:
9
package main

import (
	"flag"
	"os"

	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/file"
	"github.com/go-kratos/kratos/v2/log"

	"yourproject/internal/conf"
)

var (
	flagconf string
)

func init() {
	flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml")
}

func main() {
	flag.Parse()

	// Create config source
	c := config.New(
		config.WithSource(
			file.NewSource(flagconf),
		),
	)
	defer c.Close()

	// Load configuration
	if err := c.Load(); err != nil {
		log.Fatal(err)
	}

	// Scan configuration into struct
	var bc conf.Bootstrap
	if err := c.Scan(&bc); err != nil {
		log.Fatal(err)
	}

	// Use configuration
	log.Infof("HTTP server running on %s", bc.Server.HTTP.Addr)
	log.Infof("gRPC server running on %s", bc.Server.GRPC.Addr)
}

Multiple Configuration Sources

File + Environment Variables

Combine file and environment variable sources:
import (
	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/file"
	"github.com/go-kratos/kratos/v2/config/env"
)

c := config.New(
	config.WithSource(
		file.NewSource(flagconf),
		env.NewSource("KRATOS_"),
	),
)
Environment variables override file settings:
# Override HTTP port
export KRATOS_SERVER_HTTP_ADDR=":8080"

# Override database connection
export KRATOS_DATA_DATABASE_SOURCE="user:pass@tcp(localhost:3306)/mydb"

Remote Configuration

Load configuration from remote sources (Consul, etcd, Kubernetes ConfigMap):
import (
	"github.com/go-kratos/kratos/contrib/config/consul/v2"
	consulAPI "github.com/hashicorp/consul/api"
)

// Consul configuration source
consulClient, err := consulAPI.NewClient(&consulAPI.Config{
	Address: "127.0.0.1:8500",
})
if err != nil {
	log.Fatal(err)
}

consulSource, err := consul.New(consulClient,
	consul.WithPath("config/myapp"),
)
if err != nil {
	log.Fatal(err)
}

c := config.New(
	config.WithSource(
		consulSource,
		file.NewSource(flagconf),
	),
)

Configuration Priority

Sources are merged in order, with later sources overriding earlier ones:
c := config.New(
	config.WithSource(
		file.NewSource("configs/default.yaml"),  // Base configuration
		file.NewSource("configs/prod.yaml"),     // Environment-specific
		env.NewSource("KRATOS_"),                // Environment variables (highest priority)
	),
)

Configuration Watching

Hot-Reloading

Watch for configuration changes:
package main

import (
	"context"
	"log"

	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/file"
)

func main() {
	c := config.New(
		config.WithSource(
			file.NewSource("configs/config.yaml"),
		),
	)
	defer c.Close()

	if err := c.Load(); err != nil {
		log.Fatal(err)
	}

	// Watch for changes
	if err := c.Watch("server.http.addr", func(key string, value config.Value) {
		var addr string
		if err := value.Scan(&addr); err != nil {
			log.Printf("Failed to scan value: %v", err)
			return
		}
		log.Printf("HTTP address changed to: %s", addr)
		// Restart HTTP server with new address
	}); err != nil {
		log.Fatal(err)
	}

	select {} // Keep running
}

Watch Entire Configuration

Reload entire configuration on changes:
func watchConfig(c config.Config) {
	if err := c.Watch("", func(key string, value config.Value) {
		var bc conf.Bootstrap
		if err := c.Scan(&bc); err != nil {
			log.Printf("Failed to reload config: %v", err)
			return
		}
		log.Println("Configuration reloaded")
		// Apply new configuration
	}); err != nil {
		log.Fatal(err)
	}
}

Environment-Specific Configuration

Multiple Configuration Files

Organize configurations by environment:
configs/
├── config.yaml          # Base configuration
├── config-dev.yaml      # Development overrides
├── config-staging.yaml  # Staging overrides
└── config-prod.yaml     # Production overrides
var env = os.Getenv("ENV")
if env == "" {
	env = "dev"
}

c := config.New(
	config.WithSource(
		file.NewSource("configs/config.yaml"),
		file.NewSource(fmt.Sprintf("configs/config-%s.yaml", env)),
	),
)

Configuration Validation

Validate on Load

Validate configuration after loading:
package conf

import "errors"

func (b *Bootstrap) Validate() error {
	if b.Server.HTTP.Addr == "" {
		return errors.New("HTTP server address is required")
	}
	if b.Data.Database.Source == "" {
		return errors.New("database source is required")
	}
	return nil
}
var bc conf.Bootstrap
if err := c.Scan(&bc); err != nil {
	log.Fatal(err)
}

if err := bc.Validate(); err != nil {
	log.Fatalf("Invalid configuration: %v", err)
}

Advanced Features

Value Interpolation

Reference other configuration values:
server:
  http:
    addr: ${HOST}:${HTTP_PORT}
  grpc:
    addr: ${HOST}:${GRPC_PORT}

data:
  database:
    source: ${DB_USER}:${DB_PASS}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}

Custom Decoders

Register custom decoders for specific formats:
import (
	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/encoding"
)

// Register custom codec
encoding.RegisterCodec(myCustomCodec{})

c := config.New(
	config.WithSource(
		file.NewSource("configs/config.custom"),
	),
	config.WithDecoder(func(kv *config.KeyValue, v map[string]interface{}) error {
		// Custom decoding logic
		return nil
	}),
)

Configuration Resolver

Resolve placeholders in configuration:
c := config.New(
	config.WithSource(
		file.NewSource(flagconf),
	),
	config.WithResolver(func(input string) (string, error) {
		// Custom resolution logic
		// e.g., fetch from secrets manager
		return resolveSecret(input)
	}),
)

Best Practices

Secrets Management

Never commit secrets to version control. Use environment variables or secret managers.

Defaults

Provide sensible defaults for all configuration values.

Documentation

Document all configuration options with comments in your config files.

Validation

Always validate configuration on startup to fail fast.

Example: Complete Configuration Setup

cmd/server/main.go
package main

import (
	"context"
	"flag"
	"fmt"
	"os"

	"github.com/go-kratos/kratos/v2"
	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/env"
	"github.com/go-kratos/kratos/v2/config/file"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/transport/http"

	"yourproject/internal/conf"
)

var (
	flagconf string
)

func init() {
	flag.StringVar(&flagconf, "conf", "../../configs", "config path")
}

func main() {
	flag.Parse()

	// Initialize logger
	logger := log.NewStdLogger(os.Stdout)
	log.SetLogger(logger)

	// Load configuration
	c := config.New(
		config.WithSource(
			file.NewSource(flagconf),
			env.NewSource("KRATOS_"),
		),
	)
	defer c.Close()

	if err := c.Load(); err != nil {
		log.Fatal(err)
	}

	var bc conf.Bootstrap
	if err := c.Scan(&bc); err != nil {
		log.Fatal(err)
	}

	// Validate configuration
	if err := bc.Validate(); err != nil {
		log.Fatalf("Invalid configuration: %v", err)
	}

	// Start application
	app, cleanup, err := initApp(&bc, logger)
	if err != nil {
		log.Fatal(err)
	}
	defer cleanup()

	if err := app.Run(); err != nil {
		log.Fatal(err)
	}
}

Next Steps

Service Discovery

Configure service discovery and registration

Deployment

Deploy your configured service

Build docs developers (and LLMs) love