Forge Integration

How Forge exposes Vessel for app services and extension wiring

Forge uses Vessel as its internal dependency injection engine. Every Forge application creates a Vessel container at startup and exposes it via app.Container(). Forge also re-exports Vessel functions under the forge package for convenience, along with backward-compatible named-registration helpers.

Accessing the Container

import "github.com/xraph/forge"

app := forge.New(
    forge.WithAppName("my-app"),
    forge.WithAppVersion("1.0.0"),
)

// The container is a vessel.Vessel instance
c := app.Container()

forge.Container is a type alias for vessel.Vessel, so all Vessel functions work directly with the value returned by app.Container().

Core Services Registered by Forge

When a Forge app is created, these services are automatically registered in the container -- both by name (for backward compatibility) and by type (for constructor injection):

ServiceTypeName Key
Loggerforge.Logger"logger"
Config Managerforge.ConfigManager"forge.config"
Metricsforge.Metrics"metrics"
Health Managerforge.HealthManager"forge.health"
Routerforge.Router"forge.router"

Resolving Core Services

By type (recommended):

logger, err := forge.Inject[forge.Logger](app.Container())
metrics, err := forge.Inject[forge.Metrics](app.Container())

By name:

logger, err := forge.InjectNamed[forge.Logger](app.Container(), "logger")

Forge also provides convenience helpers:

logger, err := forge.GetLogger(app.Container())
metrics, err := forge.GetMetrics(app.Container())
healthMgr, err := forge.GetHealthManager(app.Container())

Forge Re-exports

Forge re-exports all Vessel DI functions under the forge package. You can use either vessel.* or forge.* -- they call the same underlying functions.

Constructor Registration and Resolution

Forge functionVessel equivalent
forge.Provide(c, constructor, opts...)vessel.Provide(c, constructor, opts...)
forge.ProvideConstructor(c, constructor, opts...)vessel.Provide(c, constructor, opts...)
forge.ProvideValue[T](c, value, opts...)vessel.ProvideValue[T](c, value, opts...)
forge.Inject[T](c)vessel.Inject[T](c)
forge.MustInject[T](c)vessel.MustInject[T](c)
forge.InjectNamed[T](c, name)vessel.InjectNamed[T](c, name)
forge.MustInjectNamed[T](c, name)vessel.MustInjectNamed[T](c, name)
forge.InjectGroup[T](c, group)vessel.InjectGroup[T](c, group)
forge.MustInjectGroup[T](c, group)vessel.MustInjectGroup[T](c, group)
forge.HasType[T](c)vessel.HasType[T](c)
forge.HasTypeNamed[T](c, name)vessel.HasTypeNamed[T](c, name)

Named Registration Helpers (Forge-only)

These are backward-compatible helpers that Forge provides on top of Vessel. They accept a func(Container) (T, error) factory and translate it into the appropriate vessel.ProvideNamed call.

Forge functionWhat it does
forge.RegisterSingleton[T](c, name, factory)vessel.ProvideNamed + AsSingleton()
forge.RegisterTransient[T](c, name, factory)vessel.ProvideNamed + AsTransient()
forge.RegisterScoped[T](c, name, factory)vessel.ProvideNamed + AsScoped()
forge.RegisterValue[T](c, name, value)vessel.ProvideValue + WithName(name)
forge.Resolve[T](c, name)vessel.InjectNamed[T](c, name)
forge.Must[T](c, name)vessel.MustInjectNamed[T](c, name)

Wrapper Type Aliases

Forge aliasVessel type
forge.LazyRef[T]vessel.Lazy[T]
forge.OptionalLazyRef[T]vessel.OptionalLazy[T]
forge.ProviderRef[T]vessel.Provider[T]

Factory helpers:

forge.NewLazyRef[T](c, name)         // vessel.NewLazy[T](c, name)
forge.NewOptionalLazyRef[T](c, name) // vessel.NewOptionalLazy[T](c, name)
forge.NewProviderRef[T](c, name)     // vessel.NewProvider[T](c, name)

Writing Extensions

Extensions register their services during the Register phase using the container from app.Container().

import (
    "context"
    "github.com/xraph/forge"
    "github.com/xraph/vessel"
)

type MyExtension struct {
    app forge.App
}

func (e *MyExtension) Register(app forge.App) error {
    e.app = app
    c := app.Container()

    // Register services using vessel (or forge -- equivalent)
    vessel.Provide(c, NewMyService)

    return nil
}

func (e *MyExtension) Start(ctx context.Context) error {
    svc, err := vessel.Inject[*MyService](e.app.Container())
    if err != nil {
        return err
    }
    return svc.Start(ctx)
}

func (e *MyExtension) Stop(ctx context.Context) error {
    return nil
}

Depending on Other Extensions

Use constructor injection to depend on services from other extensions. Because constructors are resolved by type, there is no need to coordinate string keys across extensions.

// This extension depends on the database extension's DatabaseManager
func NewMyService(manager *database.DatabaseManager, logger forge.Logger) (*MyService, error) {
    db, err := manager.SQL("primary")
    if err != nil {
        return nil, err
    }
    return &MyService{db: db, logger: logger}, nil
}

func (e *MyExtension) Register(app forge.App) error {
    return vessel.Provide(app.Container(), NewMyService)
}

Resolving Services During Registration

If you need a service to be fully started before using it during the Register phase, use the container's ResolveReady method:

func (e *MyExtension) Register(app forge.App) error {
    ctx := context.Background()

    svc, err := app.Container().ResolveReady(ctx, "database-manager")
    if err != nil {
        return fmt.Errorf("database required: %w", err)
    }

    dbManager := svc.(*database.DatabaseManager)
    e.redis, _ = dbManager.Redis("cache")
    return nil
}

Interface Resolution Across Extensions

Use interface types for loose coupling between extensions:

// Extension A registers a concrete implementation as an interface
vessel.Provide(app.Container(), NewEventService, vessel.As(new(core.EventBus)))

// Extension B resolves by interface type
eventBus, err := vessel.Inject[core.EventBus](app.Container())

Which Package to Import

ScenarioRecommendation
Standalone library (no Forge)import "github.com/xraph/vessel"
Forge application codeEither works; forge is convenient for type aliases
Forge extensionvessel for registration, forge for types like forge.Logger
Shared package used in bothimport "github.com/xraph/vessel"

How is this guide?

On this page