Comparing godi to Other DI Solutions

Quick comparison to help you choose the right tool.

godi vs Manual Dependency Injection

Manual DI: Wire everything yourself

// Manual DI
func main() {
    config := NewConfig()
    logger := NewLogger(config)
    db := NewDatabase(config, logger)
    cache := NewCache(config, logger)
    userRepo := NewUserRepository(db, cache, logger)
    userService := NewUserService(userRepo, logger)
    handler := NewHandler(userService, logger)

    // Manual cleanup
    defer db.Close()
    defer cache.Close()
}

godi: Automatic wiring

// godi with modules
var AppModule = godi.NewModule("app",
    godi.AddSingleton(NewConfig),
    godi.AddSingleton(NewLogger),
    godi.AddSingleton(NewDatabase),
    godi.AddSingleton(NewCache),
    godi.AddScoped(NewUserRepository),
    godi.AddScoped(NewUserService),
    godi.AddScoped(NewHandler),
)

func main() {
    services := godi.NewServiceCollection()
    services.AddModules(AppModule)

    provider, _ := services.BuildServiceProvider()
    defer provider.Close() // Automatic cleanup!

    handler, _ := godi.Resolve[*Handler](provider)
}

When to use manual DI:

  • Very small apps (< 10 services)

  • Simple CLI tools

  • Learning projects

When to use godi:

  • Web applications

  • Apps with many services

  • When you need testing

  • Request-scoped isolation

godi vs wire (Google)

wire: Compile-time code generation

// wire.go
//+build wireinject

func InitializeApp() (*App, error) {
    wire.Build(
        NewConfig,
        NewDatabase,
        NewService,
        NewApp,
    )
    return nil, nil
}

// Run: wire gen ./...
// Generates: wire_gen.go with all wiring code

godi: Runtime dependency injection with modules

// No code generation needed!
var AppModule = godi.NewModule("app",
    godi.AddSingleton(NewConfig),
    godi.AddSingleton(NewDatabase),
    godi.AddScoped(NewService),
    godi.AddScoped(NewApp),
)

// Use immediately
services := godi.NewServiceCollection()
services.AddModules(AppModule)
provider, _ := services.BuildServiceProvider()
app, _ := godi.Resolve[*App](provider)

Key differences:

Feature

wire

godi

When

Compile time

Runtime

Setup

Requires wire tool

Just import

Scoped services

❌ No

✅ Yes

Speed

Faster (no reflection)

Fast enough

Flexibility

Less (compile time)

More (runtime)

Learning curve

Steeper

Easier

Choose wire if:

  • You want zero runtime overhead

  • You don’t need scoped services

  • You’re OK with code generation

Choose godi if:

  • You need scoped services (web apps)

  • You want runtime flexibility

  • You prefer no build tools

godi vs fx (Uber)

fx: Full application framework

// fx - application lifecycle
app := fx.New(
    fx.Provide(
        NewConfig,
        NewDatabase,
        NewServer,
    ),
    fx.Invoke(func(s *Server) {
        // Automatically called on start
    }),
)

app.Run() // Blocks and manages lifecycle

godi: Just dependency injection

// godi - you control the app
var AppModule = godi.NewModule("app",
    godi.AddSingleton(NewConfig),
    godi.AddSingleton(NewDatabase),
    godi.AddSingleton(NewServer),
)

func main() {
    services := godi.NewServiceCollection()
    services.AddModules(AppModule)

    provider, _ := services.BuildServiceProvider()
    defer provider.Close()

    server, _ := godi.Resolve[*Server](provider)
    server.Run() // You control when/how
}

Key differences:

Feature

fx

godi

Scope

Full framework

Just DI

Lifecycle

Managed

Manual

Hooks

Start/Stop hooks

Constructor/Dispose

Learning

More complex

Simpler

Control

Less

More

Choose fx if:

  • You want a full framework

  • You need complex lifecycle management

  • Building microservices

Choose godi if:

  • You just want dependency injection

  • You prefer manual control

  • You like .NET-style DI

Quick Decision Guide

Need DI for Go?
    │
    ├─ Very small app?
    │   └─ Use Manual DI
    │
    ├─ Need compile-time safety + zero overhead?
    │   └─ Use wire
    │
    ├─ Need full application framework?
    │   └─ Use fx
    │
    └─ Need scoped services + simple API?
        └─ Use godi ✓

Feature Comparison

Feature

Manual

wire

fx

godi

No setup

Type safe

⚠️

Scoped services

⚠️

Runtime flexibility

Zero overhead

Testing support

⚠️

Modules

Auto disposal

Learning curve

Easy

Hard

Hard

Easy

For .NET Developers

If you’re coming from .NET, godi will feel very familiar:

.NET:

services.AddSingleton<ILogger, Logger>();
services.AddScoped<IUserService, UserService>();
var provider = services.BuildServiceProvider();
var service = provider.GetService<IUserService>();

godi:

services.AddSingleton(NewLogger)
services.AddScoped(NewUserService)
provider, _ := services.BuildServiceProvider()
service, _ := godi.Resolve[UserService](provider)

Same concepts, Go syntax!

Summary

  • Manual DI: For tiny apps

  • wire: For compile-time DI without scopes

  • fx: For full application frameworks

  • godi: For runtime DI with scopes (perfect for web apps)

Choose godi when you want simple, flexible dependency injection with support for request-scoped services!