uconfig-watchfiles

March 31, 2026 ยท View on GitHub

File watching extension for uconfig. Add watchfiles.New() to your plugins and call Watch for automatic config reload when source files change.

Usage

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"os/signal"

	"github.com/omeid/uconfig"
	"github.com/omeid/uconfig/plugins/file"

	watchfiles "github.com/omeid/uconfig-watchfiles"
)

type Config struct {
	Hosts []string `default:"localhost" usage:"bind addresses"`
	Mode  string   `default:"start" flag:",command" usage:"start|stop"`
}

var files = uconfig.Files{
	{Path: file.Relative("config.json"), Unmarshal: json.Unmarshal, Optional: true},
}

func main() {
	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
	defer cancel()

	conf := uconfig.Classic[Config](files, watchfiles.New())

	err := conf.Watch(ctx, func(ctx context.Context, c *Config) error {
		fmt.Printf("config loaded: %+v\n", c)

		// Block until told to reload or stop.
		<-ctx.Done()
		return nil

		// Return nil to exit Watch cleanly.
		// Return any other error to abort.
	})

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

The callback is called once with the initial config, then again whenever a config file changes. Changes are debounced (200ms). When a file changes, the callback's context is cancelled, the full config is re-parsed (preserving env, flags, and other sources), and the callback is called again with the new value.

watchfiles.New() is a uconfig Extension plugin. It discovers file paths from sibling file plugins and watches them with fsnotify. One watcher handles all files.

Install

go get github.com/omeid/uconfig-watchfiles

LICENSE

MIT.