Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wire

wire is a compile-time dependency-injection generator for Go 1.27. It uses generic methods to describe typed dependency graphs and emits ordinary, sequential Go code. There is no runtime container or reflection.

The module is pre-v1 and intentionally free to evolve.

Quick start

Constructors are normal Go functions. A managed constructor returns its cleanup immediately before an optional final error:

func NewDatabase(
	ctx context.Context,
	config Config,
) (*Database, func() error, error) {
	// ...
}

func NewApplication(database *Database) *Application {
	return &Application{Database: database}
}

Put graph declarations in a wireinject file so the normal application build does not import the generator module:

//go:build wireinject

package app

import (
	"context"

	"github.com/libtnb/wire"
)

var AppModule = wire.New().
	Provide(NewConfig).
	Provide(NewDatabase).
	Provide(NewApplication)

var InitializeApp = AppModule.Injector[
	func(context.Context) (*Application, func() error, error),
]()

Generate and verify wire_gen.go:

go run github.com/libtnb/wire/cmd/wire generate ./...
go run github.com/libtnb/wire/cmd/wire check ./...

API

Operation Purpose
Provide(fn) Add a constructor.
Value[T](value) Bind a side-effect-free expression as T.
Bind[I, C]() Bind concrete C to interface I.
Include(modules...) Add child modules.
Export[T]() Expose a child-owned binding; bindings are private by default.
Decorate[T](fn) Wrap the visible T.
Override[T](fn) Replace the current module's visible T.
OverrideValue[T](value) Replace T with a value expression.
Multibind[C]() Declare an empty-capable named slice or map.
Contribute[C](fn) Add a named-slice element.
ContributeMap[C](key, fn) Add a constant-keyed entry; the key is checked against C.
Scope[F](module) Add a lifecycle-bound child factory.
Injector[F]() Declare a generated entry point.

Dependency keys are exact Go types. context.Context is reserved for the first injector or scope parameter and is passed automatically to providers that accept it first.

A provider returns one or more business values, then optionally:

func() error, error

Either optional result may be omitted. The cleanup type must be that exact function type or an alias; a newly defined function type remains a business value. If a provider returns an error, it owns any partially created resource and its returned cleanup is not armed.

Construction follows dependency order on the calling goroutine. On failure or panic, already armed cleanups run in reverse order. Provider and cleanup errors are combined with errors.Join. Generated cleanups are idempotent. A panicking cleanup does not prevent later cleanups from running; the first panic is re-thrown after the remaining resources close. During error rollback a cleanup panic takes precedence over the returned error; during panic rollback the original construction panic is preserved.

Modules and scopes

Child bindings cross a module boundary only through Export. An export must be owned by that child, although its constructor dependencies may fall back to the parent. Overrides are lexical: they may shadow a local, child-exported, or parent-visible base binding without mutating another module. Decorators run after override selection and in declaration order.

Each Include creates an independent lexical module instance. Include a stateful module once at the nearest common parent when multiple children must share its resources. Named modules cannot be extended in place; start with wire.New().Include(module) to make the new boundary explicit.

A scope factory always has this shape:

type SessionFactory func(
	context.Context,
	UserID,
) (*Session, func() error, error)

Callers should release successful scopes with the returned idempotent cleanup. The parent retains a fallback cleanup until then. Parent cleanup rejects new calls, cancels and waits for active builds, closes outstanding child scopes in reverse completion order, and finally closes parent resources. A factory rejects an already-canceled context before constructing providers.

Command

wire generate [-tags list] [packages]  update generated files
wire check    [-tags list] [packages]  fail when generated files are stale
wire diff     [-tags list] [packages]  print generated-file differences
wire show     [-tags list] [packages]  print resolved graphs
wire version                           print the version
wire help                              print command usage

Diagnostics have WIRE#### codes and support JSON Lines with -json. The command only overwrites or removes files carrying its generated ownership header. The internal wireinject tag is reserved and must not be passed through -tags.

Conditional injectors, providers, and type declarations produce separate owned files. The generator derives each variant's build constraint from the source declarations it uses, keeps inactive variants, and checks or removes only the variant active for the requested -tags, GOOS, and GOARCH configuration. Unconditional graphs continue to use wire_gen.go.

libtnb/wire is an independent MIT-licensed implementation inspired by Google Wire's compile-time model.

About

Compile-time Dependency Injection for Go

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages