Injection Scopes

Every provider in GoNest has a scope that determines its lifetime. Understanding scopes is essential for managing state and performance in your application. Equivalent to NestJS injection scopes.

Available Scopes

ScopeConstantDescription
SingletonScopeSingletonOne shared instance for the entire application (default)
RequestScopeRequestA new instance is created for each incoming HTTP request
TransientScopeTransientA new instance is created every time the provider is injected

Singleton Scope (Default)

Singleton providers are created once and shared everywhere. This is the default and the most efficient scope.

// These are all singletons:
gonest.Provide(NewCatsService)
gonest.ProvideValue[*Config](cfg)
gonest.ProvideFactory[*DB](NewDBConnection)

Use singletons for:

Request Scope

Request-scoped providers get a fresh instance per HTTP request. Useful when you need per-request state.

gonest.ProvideWithScope(NewRequestLogger, gonest.ScopeRequest)
type RequestLogger struct {
    requestID string
}

func NewRequestLogger() *RequestLogger {
    return &RequestLogger{
        requestID: uuid.New().String(),
    }
}

Every handler in the same request receives the same RequestLogger instance, but different requests get different instances.

Transient Scope

Transient providers create a new instance every time they are injected. No instance is shared.

gonest.ProvideWithScope(NewWorker, gonest.ScopeTransient)

Use transient scope when each consumer needs its own independent instance.

Scope Propagation

Scopes propagate through the dependency chain. If a singleton depends on a request-scoped provider, the singleton is automatically elevated to request scope.

// RequestService is request-scoped
gonest.ProvideWithScope(NewRequestService, gonest.ScopeRequest)

// CatsService depends on RequestService
// Even though CatsService is registered as singleton, it becomes
// request-scoped because its dependency is request-scoped.
gonest.Provide(NewCatsService) // func NewCatsService(rs *RequestService) *CatsService

This ensures correctness: a singleton would otherwise hold a stale reference to a request-scoped dependency.

The container resolves the effective scope by taking the broadest scope in the dependency chain:

Performance Considerations

Default to singleton unless you have a specific reason to use request or transient scope. Most services are stateless and work perfectly as singletons.