confx

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 20, 2026 License: MIT Imports: 6 Imported by: 0

README

confx

Go Reference CI Release

Install · Quick start · How it works · Configuration · Examples

The Uber Fx adapter for confmaker: it loads configs when the application starts and provides them to the Fx container.

Installation

Requires Go 1.27 or later.

go get github.com/uchaloop/confx@v0.1.0

Declaring configs, tags, JSON values, the manifest and the dump are described in the confmaker README and its package documentation.

Quick start

package main

import (
    "fmt"

    "github.com/uchaloop/confx"
    "go.uber.org/fx"
)

type Config struct {
    Port int `env:"PORT"`
}

func (Config) ConfigName() string { return "server" }
func (c *Config) SetDefaults() { c.Port = 8080 }

func main() {
    fx.New(
        confx.Module(),
        confx.Provide[Config](), // SERVER_PORT, default 8080
        fx.Invoke(func(cfg Config) { fmt.Println(cfg.Port) }),
    ).Run()
}

Module is required once. Configurations are loaded during dependency resolution, including registrations with no consumer. Loading errors prevent successful startup. The configuration type has no dependency on Fx or confmaker.

Registration What the consumer receives
Provide[Config]() Untagged Config
ProvideNamed[Config]("replica") Config with Fx tag name:"replica"
Two configurations of the same type
confx.Provide[Config](),
confx.ProvideNamed[Config]("replica"), // REPLICA_PORT
type Params struct {
    fx.In
    Primary Config
    Replica Config `name:"replica"`
}

How it works

flowchart LR
    A["Module: one loader"] --> C["Register every configuration"]
    B["Provide / ProvideNamed"] --> C
    C --> D["Load and validate together"]
    D -->|success| E["Typed values in Fx"]
    D -->|error| F["Fail application construction/startup"]

[!NOTE] WithName changes the configuration instance name. Only ProvideNamed adds an Fx name tag. These are separate mechanisms.

Name, prefix and tag

These are three different things:

Comes from Used for
instance name ConfigName, confmaker.WithName, or the ProvideNamed name the default prefix and errors
ENV prefix the instance name (replica → REPLICA_), or confmaker.WithPrefix variable names
Fx tag ProvideNamed only how consumers ask for the value

Provide with confmaker.WithName changes the name and prefix but adds no Fx tag. ProvideNamed refuses a further WithName.

Module takes the options of confmaker.MakeLoader, such as confmaker.WithDump(os.Stdout) or confmaker.WithEnv(vars) in tests.

Documentation

pkg.go.dev/github.com/uchaloop/confx

[!TIP] We recommend confmaker for typed ENV configuration and confx for its Fx integration. Configuration loading stays in the application; it is optional for the work libraries.

Configure from ENV with confmaker / confx

The pair separates configuration declarations from application wiring. A library declares an ordinary struct; the application chooses how to load it:

type Config struct {
    Port int `env:"PORT"`
}

func (Config) ConfigName() string { return "server" }
func (c *Config) SetDefaults() { c.Port = 8080 }

Without Fx:

cfg, err := confmaker.Load[Config]() // SERVER_PORT, default 8080

With Fx:

confx.Module(),
confx.Provide[Config](),

Import github.com/uchaloop/confmaker for the loader or github.com/uchaloop/confx for the Fx adapter.

Library Purpose
confmaker ENV tags, validation, manifest and dump
jobfx One-shot work through Fx
beatfx Recurring work through Fx

Acknowledgements

Thanks to the authors and maintainers of Uber Fx for dependency injection and lifecycle primitives that make this adapter possible.

License

MIT

Documentation

Overview

Package confx provides configs loaded by github.com/uchaloop/confmaker to an Uber Fx application.

fx.New(
	confx.Module(),
	confx.Provide[postgres.Config](),
	confx.ProvideNamed[postgres.Config]("replica", confmaker.WithPrefix("REPLICA_POSTGRES_")),
)

Module creates one confmaker.Loader per application and is required. Provide registers a config and provides it untagged; ProvideNamed provides it under the Fx tag name:"<name>". Every provided config is loaded when the application starts, whether or not anything consumes it, and the start fails with one error listing every problem.

Declaring configs, the options and the loading rules are documented in package confmaker.

Example

Provide makes the config available to constructors. WithEnv stands in for the process environment here; an application calls confx.Module() without it.

package main

import (
	"fmt"
	"time"

	"github.com/uchaloop/confmaker"
	"github.com/uchaloop/confx"
	"go.uber.org/fx"
)

// StoreConfig is the kind of config a library declares: plain fields, env tags,
// and no knowledge of where the values come from.
type StoreConfig struct {
	Host    string        `env:"HOST,notEmpty"`
	Timeout time.Duration `env:"TIMEOUT"`
}

func (StoreConfig) ConfigName() string { return "store" }

func (c *StoreConfig) SetDefaults() { c.Timeout = 30 * time.Second }

func main() {
	env := confmaker.WithEnv(map[string]string{"STORE_HOST": "db:5432"})

	app := fx.New(
		fx.NopLogger,
		confx.Module(env),
		confx.Provide[StoreConfig](),
		fx.Invoke(func(cfg StoreConfig) {
			fmt.Println(cfg.Host, cfg.Timeout)
		}),
	)
	if err := app.Err(); err != nil {
		fmt.Println(err)
	}

}
Output:
db:5432 30s

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Module

func Module(opts ...confmaker.EnvOption) fx.Option

Module loads the configs registered by Provide and ProvideNamed through one confmaker.Loader per application, configured by opts. Loading happens once, when the application starts or when a constructor first needs a config, and its error lists the problems of every config, whatever order the options are given in.

An application that calls Provide or ProvideNamed must include Module exactly once.

func Provide

func Provide[T any](opts ...confmaker.ConfigOption) fx.Option

Provide registers a config of type T with Module and provides it without an Fx tag. The instance name comes from confmaker.WithName or T's ConfigName; WithName adds no Fx tag. The config is loaded at start whether or not anything consumes it.

func ProvideNamed

func ProvideNamed[T any](name string, opts ...confmaker.ConfigOption) fx.Option

ProvideNamed registers a config of type T with Module and provides it with the Fx tag name:"<name>". name is also the instance name, and gives the prefix unless confmaker.WithPrefix changes it. ConfigName is not used, and a further WithName is reported as an error.

Example

ProvideNamed provides a second instance of the same type under an Fx tag, with its own prefix.

package main

import (
	"fmt"
	"time"

	"github.com/uchaloop/confmaker"
	"github.com/uchaloop/confx"
	"go.uber.org/fx"
)

// StoreConfig is the kind of config a library declares: plain fields, env tags,
// and no knowledge of where the values come from.
type StoreConfig struct {
	Host    string        `env:"HOST,notEmpty"`
	Timeout time.Duration `env:"TIMEOUT"`
}

func (StoreConfig) ConfigName() string { return "store" }

func (c *StoreConfig) SetDefaults() { c.Timeout = 30 * time.Second }

func main() {
	env := confmaker.WithEnv(map[string]string{
		"STORE_HOST":         "db:5432",
		"REPLICA_STORE_HOST": "replica:5432",
	})

	type params struct {
		fx.In

		Primary StoreConfig
		Replica StoreConfig `name:"replica"`
	}

	app := fx.New(
		fx.NopLogger,
		confx.Module(env),
		confx.Provide[StoreConfig](),
		confx.ProvideNamed[StoreConfig]("replica", confmaker.WithPrefix("REPLICA_STORE_")),
		fx.Invoke(func(p params) {
			fmt.Println(p.Primary.Host, p.Replica.Host)
		}),
	)
	if err := app.Err(); err != nil {
		fmt.Println(err)
	}

}
Output:
db:5432 replica:5432

Types

This section is empty.

Jump to

Keyboard shortcuts

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