| name | implementation-lokstra-init-framework |
| description | Initialize Lokstra Framework in main.go. Setup lokstra_init.BootstrapAndRun(), service registration, and configuration loading. Use after design-lokstra-overview to create working application entry point. |
| phase | implementation |
| order | 1 |
| license | MIT |
| compatibility | {"lokstra_version":">=0.1.0","go_version":">=1.18"} |
| references | ["references/01-basic-main.go","references/02-with-options-main.go","references/03-multi-module-main.go","references/04-custom-router-main.go","references/05-initialization-options.md","references/06-startup-flow.md","references/07-troubleshooting.md"] |
Implementation: Lokstra Framework Initialization
Overview
This skill teaches you how to initialize the Lokstra Framework in main.go. The framework uses a convention-over-configuration approach with automatic code generation from annotations. Unlike traditional Go web frameworks, you don't manually register routes - they're discovered from @Handler and @Route annotations.
When to Use
Use this skill when:
- ✅ Starting a new Lokstra project and need to create
main.go
- ✅ Setting up framework initialization with middleware and services
- ✅ Configuring database connections and migrations
- ✅ Setting up multi-module applications with dependency injection
- ✅ Configuring development vs production environments
Prerequisites:
- ✅ Project structure created (
configs/, modules/ folders)
- ✅
config.yaml file exists in configs/ folder
- ✅ At least 1 module with
@Handler annotation
- ✅
go.mod initialized with lokstra dependency
go mod init myapp
go get github.com/primadi/lokstra
Basic Setup (main.go)
Minimal Configuration
The simplest working main.go for a Lokstra application:
package main
import (
"github.com/primadi/lokstra/lokstra_init"
"github.com/primadi/lokstra/middleware/recovery"
"github.com/primadi/lokstra/middleware/request_logger"
"github.com/primadi/lokstra/services/dbpool_pg"
)
func main() {
recovery.Register()
request_logger.Register()
dbpool_pg.Register()
lokstra_init.BootstrapAndRun()
}
What Happens:
- Middleware Registration - Registers middleware in the framework registry (order matters!)
- Service Registration - Registers service factory functions for later instantiation
- BootstrapAndRun() - Performs the following:
- Scans for
@Handler and @Service annotations
- Generates route registration code (
zz_generated.lokstra.go)
- Loads
configs/*.yaml files (auto-merged)
- Creates services in dependency order
- Creates
@Handler instances with dependency injection
- Mounts HTTP routes
- Starts server on configured address
Note: You do NOT need to call lokstra.Bootstrap() manually. It's called internally by BootstrapAndRun().
Reference: See references/01-basic-main.go for complete example.
Multi-Module Setup
For applications with multiple Domain-Driven Design (DDD) modules:
package main
import (
"github.com/primadi/lokstra/lokstra_init"
"github.com/primadi/lokstra/middleware/recovery"
"github.com/primadi/lokstra/middleware/request_logger"
"github.com/primadi/lokstra/services/dbpool_pg"
)
func main() {
recovery.Register()
request_logger.Register()
dbpool_pg.Register()
lokstra_init.BootstrapAndRun()
}
Important: You do NOT need to manually import module packages! Module imports are automatically generated in zz_lokstra_imports.go during bootstrap.
How It Works:
BootstrapAndRun() scans all directories for @Handler and @Service annotations
- Generates
zz_lokstra_imports.go at project root with all required imports
- Auto-restarts the application if code changes (dev mode only)
- All modules are automatically discovered and registered
Project Structure:
myapp/
├── main.go # Your clean main file (no module imports!)
├── zz_lokstra_imports.go # AUTO-GENERATED - contains all module imports
├── configs/
│ └── config.yaml
└── modules/
├── auth/
│ └── application/
│ ├── handler.go
│ └── zz_generated.lokstra.go # AUTO-GENERATED
├── user/
│ └── application/
│ ├── handler.go
│ └── zz_generated.lokstra.go # AUTO-GENERATED
└── order/
└── application/
├── handler.go
└── zz_generated.lokstra.go # AUTO-GENERATED
Reference: See references/03-multi-module-main.go for complete example.
Advanced Configuration with Options
Customize framework behavior using initialization options:
package main
import (
"fmt"
"github.com/primadi/lokstra/common/logger"
"github.com/primadi/lokstra/lokstra_init"
"github.com/primadi/lokstra/middleware/cors"
"github.com/primadi/lokstra/middleware/gzipcompression"
"github.com/primadi/lokstra/middleware/recovery"
"github.com/primadi/lokstra/middleware/request_logger"
"github.com/primadi/lokstra/services/dbpool_pg"
"github.com/primadi/lokstra/services/eventbus"
"github.com/primadi/lokstra/services/kvstore"
)
func main() {
recovery.Register()
request_logger.Register()
cors.Register([]string{"*"})
gzipcompression.Register()
dbpool_pg.Register()
eventbus.Register()
kvstore.Register()
if err := lokstra_init.BootstrapAndRun(
lokstra_init.WithLogLevel(logger.LogLevelDebug),
lokstra_init.WithDbMigrations(true, "migrations"),
lokstra_init.WithPgSyncMap(true, "db_main"),
lokstra_init.WithServerInitFunc(func() error {
fmt.Println("╔════════════════════════════════════╗")
fmt.Println("║ Server Initializing... ║")
fmt.Println("╚════════════════════════════════════╝")
return nil
}),
); err != nil {
panic("Failed to initialize: " + err.Error())
}
}
Available Options:
| Option | Description | Default |
|---|
WithLogLevel(level) | Set logging level | logger.LogLevelInfo |
WithDbMigrations(enable, folder) | Auto-run migrations on startup | false, "migrations" |
WithPgSyncMap(enable, dbPool) | Distributed config sync | false, "db_main" |
WithServerInitFunc(fn) | Custom initialization hook | nil |
WithYAMLConfigPath(enable, paths...) | Custom config paths | true, "configs" |
WithAnnotations(enable, paths...) | Annotation scanning | true, current dir |
WithAutoRunServer(enable) | Auto-start server | true |
WithPanicOnConfigError(enable) | Panic on config error | true |
Reference:
Configuration File Structure
Lokstra requires a config.yaml in the configs/ folder. This defines services and deployment configurations.
Minimal config.yaml
service-definitions:
db_main:
type: dbpool_pg
config:
dsn: ${DB_DSN:postgres://user:pass@localhost:5432/mydb}
schema: ${DB_SCHEMA:public}
deployments:
development:
servers:
api:
addr: ":8080"
published-services:
- user-handler
- auth-handler
Key Sections:
- service-definitions - Infrastructure services (DB pools, caches, queues)
- deployments - Server configurations per environment
- published-services - List of
@Handler names to expose in this server
Note: Multiple YAML files in configs/ folder are automatically merged. Use this for:
configs/base.yaml - Shared configuration
configs/development.yaml - Dev overrides
configs/production.yaml - Prod overrides
Middleware Registration
Registration Order Matters!
Middleware is applied in reverse order of registration:
recovery.Register()
request_logger.Register()
cors.Register([]string{"*"})
auth.Register()
Recommended Middleware Order
recovery.Register()
request_logger.Register()
cors.Register([]string{"*"})
gzipcompression.Register()
auth_middleware.Register()
rate_limiter.Register()
tenant_resolver.Register()
Why this order?
- Recovery first - Catches panics from all middleware
- Logging early - Captures all request details
- CORS before auth - OPTIONS preflight doesn't need auth
- Auth before business logic - Protect endpoints
Service Registration Pattern
Built-in Services
import (
"github.com/primadi/lokstra/services/dbpool_pg"
"github.com/primadi/lokstra/services/eventbus"
"github.com/primadi/lokstra/services/kvstore"
"github.com/primadi/lokstra/services/metrics_prometheus"
)
func main() {
dbpool_pg.Register()
eventbus.Register()
kvstore.Register()
metrics_prometheus.Register()
lokstra_init.BootstrapAndRun()
}
Custom Service Registration
For custom @Service annotations, register the service factory:
import "github.com/primadi/lokstra/lokstra_registry"
func RegisterUserServices() {
lokstra_registry.RegisterServiceFactory("user-repository", NewUserRepository)
}
import "myapp/modules/user/infrastructure"
func main() {
infrastructure.RegisterUserServices()
lokstra_init.BootstrapAndRun()
}
Note: Most custom services use @Service annotations and don't require manual registration.
Environment Detection
Lokstra automatically detects the runtime environment:
| Mode | Detection | Behavior |
|---|
| Production | Compiled binary | No code generation, optimized |
| Development | go run . | Auto code generation, hot reload |
| Debug | go run . -debug or Delve | Auto code generation, debugger support |
Force Code Generation
Use --generate-only flag to generate code without starting server:
go run . --generate-only
ls modules/user/application/zz_generated.lokstra.go
ls zz_lokstra_imports.go
Generated Files:
zz_generated.lokstra.go - Per-module route registration code
zz_lokstra_imports.go - Auto-generated module imports (project root)
Use Cases:
- CI/CD pipelines
- Pre-commit hooks
- Debugging annotation issues
- Manual code generation
Advanced: Custom Router Registration
For complex deployments with multiple routers, use WithServerInitFunc:
package main
import (
"fmt"
"github.com/primadi/lokstra/lokstra_init"
"github.com/primadi/lokstra/lokstra_registry"
"github.com/primadi/lokstra/middleware/recovery"
"github.com/primadi/lokstra/services/dbpool_pg"
)
func main() {
recovery.Register()
dbpool_pg.Register()
if err := lokstra_init.BootstrapAndRun(
lokstra_init.WithServerInitFunc(func() error {
fmt.Println("Registering custom routers...")
registerRouters()
registerMiddlewareTypes()
return nil
}),
); err != nil {
panic("Failed to initialize: " + err.Error())
}
}
func registerRouters() {
apiRouter := lokstra.NewRouter("api-router")
adminRouter := lokstra.NewRouter("admin-router")
lokstra_registry.RegisterRouter("api-router", apiRouter)
lokstra_registry.RegisterRouter("admin-router", adminRouter)
}
func registerMiddlewareTypes() {
lokstra_registry.RegisterMiddlewareType("auth", NewAuthMiddleware)
lokstra_registry.RegisterMiddlewareType("rate-limit", NewRateLimitMiddleware)
}
Use Cases for ServerInitFunc:
- Multi-router deployments
- Custom middleware type registration
- Dynamic service configuration
- Environment-specific initialization
- Pre-startup validation
Reference: See references/04-custom-router-main.go for complete example.
Startup Flow Deep Dive
Understanding the complete bootstrap sequence:
┌─────────────────────────────────────┐
│ 1. main() execution starts │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 2. Middleware Registration │
│ - recovery.Register() │
│ - request_logger.Register() │
│ - Custom middleware │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 3. Service Registration │
│ - dbpool_pg.Register() │
│ - eventbus.Register() │
│ - Custom services │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 4. lokstra_init.BootstrapAndRun() │
└─────────────────────────────────────┘
↓
┌─────────────────────────┐
│ 4.1 Environment Detection│
│ prod/dev/debug mode │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.2 Code Generation │
│ Scan @Handler │
│ Generate routes │
│ Generate imports │
│ (zz_lokstra_imports)│
│ Auto-restart if ↑ │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.3 Config Loading │
│ Load configs/*.yaml │
│ Merge YAML files │
│ Substitute ${ENV} │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.4 DB Migrations │
│ Run .up.sql files │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.5 Service Creation │
│ Resolve deps graph │
│ Inject dependencies │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.6 Handler Creation │
│ Create @Handler │
│ Inject @Service │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.7 ServerInitFunc │
│ Custom init hook │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.8 Route Mounting │
│ Mount @Route │
│ Apply middleware │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 4.9 Server Start │
│ Bind address │
│ Start HTTP listener │
└─────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 5. Server Running ✅ │
│ Ready to accept requests │
└─────────────────────────────────────┘
Key Points:
- Code Generation (dev/debug only) - Scans annotations and generates route registration code
- Auto-restart - If code changed, restarts with
go run or debugger
- Dependency Resolution - Services created in topological order based on dependencies
- Fail-Fast - Panics on configuration errors by default (configurable)
Reference: See references/06-startup-flow.md for detailed flow documentation.
Common Issues and Solutions
Issue: "no published-services found"
Cause: No @Handler annotations discovered.
Solutions:
- Verify
@Handler annotation syntax:
- Ensure handler files are in correct location:
modules/user/application/handler.go
- Force regeneration:
go run . --generate-only
- Check generated imports file:
cat zz_lokstra_imports.go
Issue: Service Not Found Error
Cause: Service injected but never registered or defined in config.
Solutions:
- Add service to
configs/config.yaml:
service-definitions:
user-repo:
type: user_repository
config: {}
- Verify
@Service annotation exists
- Check
published-services list includes the handler
Issue: Port Already in Use
Solutions:
- Change port in
configs/config.yaml:
deployments:
development:
servers:
api:
addr: ":8081"
- Kill process using port:
netstat -ano | findstr :8080
taskkill /PID <PID> /F
lsof -ti:8080 | xargs kill -9
Issue: Database Connection Failed
Solutions:
- Check DSN in
configs/config.yaml:
service-definitions:
db_main:
config:
dsn: "postgres://user:pass@localhost:5432/mydb"
- Use environment variables:
dsn: ${DB_DSN:postgres://localhost:5432/mydb}
- Verify database is running:
pg_isready -h localhost -p 5432
Reference: See references/07-troubleshooting.md for comprehensive troubleshooting guide.
Testing Your Setup
1. Verify Framework Initialization
go run .
2. Test Health Endpoint
curl http://localhost:8080/health
3. Force Code Generation
go run . --generate-only
ls modules/*/application/zz_generated.lokstra.go
ls zz_lokstra_imports.go
4. Enable Debug Logging
lokstra_init.BootstrapAndRun(
lokstra_init.WithLogLevel(logger.LogLevelDebug),
)
Complete Example: Enterprise Application
Here's a complete production-ready main.go:
package main
import (
"fmt"
"github.com/primadi/lokstra/common/logger"
"github.com/primadi/lokstra/lokstra_init"
"github.com/primadi/lokstra/middleware/cors"
"github.com/primadi/lokstra/middleware/gzipcompression"
"github.com/primadi/lokstra/middleware/recovery"
"github.com/primadi/lokstra/middleware/request_logger"
"github.com/primadi/lokstra/middleware/slow_request_logger"
"github.com/primadi/lokstra/services/dbpool_pg"
"github.com/primadi/lokstra/services/eventbus"
"github.com/primadi/lokstra/services/kvstore"
)
func main() {
recovery.Register()
request_logger.Register()
slow_request_logger.Register()
cors.Register([]string{"https://app.example.com", "https://admin.example.com"})
gzipcompression.Register()
dbpool_pg.Register()
eventbus.Register()
kvstore.Register()
if err := lokstra_init.BootstrapAndRun(
lokstra_init.WithLogLevel(logger.LogLevelInfo),
lokstra_init.WithDbMigrations(true, "migrations"),
lokstra_init.WithPgSyncMap(true, "db_main"),
lokstra_init.WithServerInitFunc(func() error {
printBanner()
return nil
}),
); err != nil {
panic("❌ Failed to start application: " + err.Error())
}
}
func printBanner() {
fmt.Println("")
fmt.Println("╔════════════════════════════════════════╗")
fmt.Println("║ Enterprise Application v1.0.0 ║")
fmt.Println("║ Powered by Lokstra Framework ║")
fmt.Println("╚════════════════════════════════════════╝")
fmt.Println("")
}
Corresponding configs/config.yaml:
service-definitions:
db_main:
type: dbpool_pg
config:
dsn: ${DB_DSN:postgres://user:pass@localhost:5432/myapp}
schema: ${DB_SCHEMA:public}
max_connections: ${DB_MAX_CONN:25}
min_connections: ${DB_MIN_CONN:5}
eventbus_main:
type: eventbus
kvstore_main:
type: kvstore
config:
type: ${KVSTORE_TYPE:memory}
redis_url: ${REDIS_URL}
deployments:
development:
servers:
api:
addr: ":8080"
published-services:
- auth-handler
- user-handler
- product-handler
- order-handler
- payment-handler
- notification-handler
production:
servers:
api:
addr: ":8080"
published-services:
- auth-handler
- user-handler
- product-handler
- order-handler
- payment-handler
- notification-handler
Next Steps
After setting up main.go, proceed with these skills in order:
-
Configuration → implementation-lokstra-yaml-config
- Setup
configs/config.yaml
- Configure service definitions
- Define deployment environments
-
Database Schema → design-lokstra-schema-design
- Design PostgreSQL schema
- Create migration files
-
Services → implementation-lokstra-create-service
- Create
@Service annotated repositories
- Implement data access layer
-
Handlers → implementation-lokstra-create-handler
- Create
@Handler annotated HTTP endpoints
- Implement business logic
-
Testing → advanced-lokstra-tests
- Unit tests
- Integration tests
- Mocks
Quick Reference
Essential Imports
"github.com/primadi/lokstra/lokstra_init"
"github.com/primadi/lokstra/middleware/recovery"
"github.com/primadi/lokstra/middleware/request_logger"
"github.com/primadi/lokstra/middleware/cors"
"github.com/primadi/lokstra/services/dbpool_pg"
"github.com/primadi/lokstra/services/eventbus"
"github.com/primadi/lokstra/common/logger"
Common Patterns
recovery.Register()
lokstra_init.BootstrapAndRun()
dbpool_pg.Register()
lokstra_init.BootstrapAndRun(
lokstra_init.WithDbMigrations(true, "migrations"),
)
lokstra_init.BootstrapAndRun(
lokstra_init.WithServerInitFunc(func() error {
return nil
}),
)
lokstra_init.BootstrapAndRun(
lokstra_init.WithLogLevel(logger.LogLevelDebug),
)
Resources
Reference Files:
Related Skills:
Summary
✅ Framework Initialization - Use lokstra_init.BootstrapAndRun()
✅ NO Manual Module Imports - Auto-generated in zz_lokstra_imports.go
✅ Middleware Registration - Register in correct order (recovery first)
✅ Service Registration - Register infrastructure services
✅ Configuration - Setup configs/config.yaml with service definitions
✅ Options - Customize with WithLogLevel, WithDbMigrations, etc.
✅ Environment Detection - Auto-detects prod/dev/debug mode
✅ Code Generation - Automatic in dev mode, manual with --generate-only
The Lokstra Framework handles route registration, dependency injection, module discovery, and service lifecycle automatically. Focus on writing @Handler and @Service annotated code - the framework does the rest!