The LastBackend Toolkit plugin system provides seamless integration with external services through a unified interface. Plugins handle initialization, configuration, lifecycle management, and provide type-safe interfaces for your application code.
Plugins are declared using toolkit annotations:
// Database plugin
option (toolkit.plugins) = {
prefix: "pgsql" // Environment variable prefix
plugin: "postgres_gorm" // Plugin type from toolkit-plugins
};
// Cache plugin
option (toolkit.plugins) = {
prefix: "cache"
plugin: "redis"
};The toolkit generates:
- Plugin interfaces for dependency injection
- Plugin initialization code
- Environment variable parsing
- Lifecycle management hooks
Plugins automatically parse environment variables:
# PostgreSQL plugin (prefix: "pgsql")
MYSERVICE_PGSQL_HOST=localhost
MYSERVICE_PGSQL_PORT=5432
MYSERVICE_PGSQL_USERNAME=user
MYSERVICE_PGSQL_PASSWORD=secret
# Redis plugin (prefix: "cache")
MYSERVICE_CACHE_HOST=localhost
MYSERVICE_CACHE_PORT=6379Plugins are automatically injected into your components:
func NewRepository(app toolkit.Service, db servicepb.PgsqlPlugin) *Repository {
return &Repository{
db: db.DB(), // *gorm.DB ready to use
log: app.Log(),
}
}| Plugin | Package | Purpose | Interface |
|---|---|---|---|
| postgres_gorm | postgres_gorm |
PostgreSQL with GORM ORM | Plugin.DB() *gorm.DB |
| postgres_pg | postgres_pg |
PostgreSQL with go-pg | Plugin.DB() *pg.DB |
| postgres_pgx | postgres_pgx |
PostgreSQL with pgx driver | Plugin.DB() *pgxpool.Pool |
| redis | redis |
Redis cache/pub-sub | Plugin.Client() redis.Cmdable |
| rabbitmq | rabbitmq |
Message queue | Plugin.Publish/Subscribe |
| centrifuge | centrifuge |
Real-time messaging | Plugin.Node() *centrifuge.Node |
| sentry | sentry |
Error monitoring | Error tracking integration |
| resolver_consul | resolver_consul |
Service discovery | Consul integration |
Plugins follow a structured lifecycle:
- Initialization - Plugin instances created with configuration
- PreStart - Connections established, resources initialized
- OnStart - Background processes started (async)
- Running - Plugin available for use
- OnStop - Graceful shutdown, resources cleaned up
Environment variables follow this pattern:
{SERVICE_PREFIX}_{PLUGIN_PREFIX}_{SETTING_NAME}
Example:
- Service prefix:
USER_SERVICE(fromruntime.WithEnvPrefix) - Plugin prefix:
PGSQL(from proto declaration) - Setting:
HOST - Result:
USER_SERVICE_PGSQL_HOST=localhost
You can use multiple instances of the same plugin type:
// Primary database
option (toolkit.plugins) = {
prefix: "primary_db"
plugin: "postgres_gorm"
};
// Analytics database
option (toolkit.plugins) = {
prefix: "analytics_db"
plugin: "postgres_gorm"
};
// Session cache
option (toolkit.plugins) = {
prefix: "session_cache"
plugin: "redis"
};
// Data cache
option (toolkit.plugins) = {
prefix: "data_cache"
plugin: "redis"
};Determine which plugins your service needs:
- Database: Choose between GORM, go-pg, or pgx
- Cache: Redis for most use cases
- Message Queue: RabbitMQ for reliable messaging
- Real-time: Centrifuge for WebSocket connections
- Monitoring: Sentry for error tracking
option (toolkit.plugins) = {
prefix: "pgsql"
plugin: "postgres_gorm"
};
option (toolkit.plugins) = {
prefix: "cache"
plugin: "redis"
};MYSERVICE_PGSQL_HOST=localhost
MYSERVICE_PGSQL_USERNAME=user
MYSERVICE_PGSQL_PASSWORD=secret
MYSERVICE_CACHE_HOST=localhost
MYSERVICE_CACHE_PORT=6379func NewRepository(app toolkit.Service, db servicepb.PgsqlPlugin) *Repository {
return &Repository{db: db.DB()}
}
func (r *Repository) CreateUser(ctx context.Context, user *User) error {
return r.db.WithContext(ctx).Create(user).Error
}// ✅ Good - clear purpose
option (toolkit.plugins) = { prefix: "user_db", plugin: "postgres_gorm" };
option (toolkit.plugins) = { prefix: "session_cache", plugin: "redis" };
// ❌ Bad - unclear purpose
option (toolkit.plugins) = { prefix: "db1", plugin: "postgres_gorm" };
option (toolkit.plugins) = { prefix: "cache1", plugin: "redis" };func (s *Service) GetUser(ctx context.Context, id string) (*User, error) {
// Try cache first (non-critical)
if cached := s.getCachedUser(ctx, id); cached != nil {
return cached, nil
}
// Fallback to database (critical)
user, err := s.repo.GetUser(ctx, id)
if err != nil {
return nil, err
}
// Update cache (best effort)
s.cacheUser(ctx, user)
return user, nil
}- Critical plugins (database): Fail service startup if unavailable
- Non-critical plugins (cache): Degrade gracefully if unavailable
func (s *Server) HealthCheck(ctx context.Context, req *HealthCheckRequest) (*HealthCheckResponse, error) {
status := "healthy"
// Check critical plugins
if err := s.db.DB().Raw("SELECT 1").Error; err != nil {
return nil, status.Error(codes.Unavailable, "database unhealthy")
}
// Check non-critical plugins (don't fail)
if err := s.cache.Client().Ping(ctx).Err(); err != nil {
s.app.Log().Warn("cache unavailable")
}
return &HealthCheckResponse{Status: status}, nil
}- Available Plugins - Detailed documentation for each plugin
- Plugin Development - Guide for creating custom plugins
- Complete Plugin Guide - Comprehensive plugin system documentation
See the examples directory for real-world plugin usage:
- service/ - PostgreSQL + Redis + RabbitMQ
- gateway/ - Plugin-free API gateway
- wss/ - Redis + Centrifuge for real-time features
- Discord: Join our community
- Issues: Report plugin issues
- Plugin Repository: toolkit-plugins
The plugin system eliminates infrastructure boilerplate and lets you focus on business logic while maintaining type safety and clean architecture.