Skip to main content

Overview

The Option type implements the functional options pattern for configuring Server instances. Options control PocketBase initialization, developer mode, and configuration injection.

Type Definition

type Option func(*options)
Location: core/server/server_options.go:23 The Option type is a function that modifies internal server options. Multiple options can be passed to New() and are applied in order.

Available Options

WithConfig

Sets the PocketBase configuration to use when creating a new PocketBase instance.
func WithConfig(config *pocketbase.Config) Option
Parameters:
config
*pocketbase.Config
required
PocketBase configuration object. Supports all standard PocketBase config options including DefaultDev, DefaultDataDir, DefaultDebug, etc.
Example:
import (
    "github.com/magooney-loon/pb-ext/core"
    "github.com/pocketbase/pocketbase"
)

config := &pocketbase.Config{
    DefaultDev:     true,
    DefaultDataDir: "./custom_pb_data",
    DefaultDebug:   false,
}

srv := core.New(core.WithConfig(config))
Location: core/server/server_options.go:27
Cannot be used with WithPocketbase. These options are mutually exclusive. Using both will cause a panic with ErrConfigurationConflict.

WithPocketbase

Sets a fully initialized PocketBase instance to wrap instead of creating a new one.
func WithPocketbase(pb *pocketbase.PocketBase) Option
Parameters:
pb
*pocketbase.PocketBase
required
Pre-initialized PocketBase instance. Useful when you need full control over PocketBase initialization or want to share an instance.
Example:
import (
    "github.com/magooney-loon/pb-ext/core"
    "github.com/pocketbase/pocketbase"
)

// Create and configure PocketBase manually
pb := pocketbase.NewWithConfig(pocketbase.Config{
    DefaultDev:     true,
    DefaultDataDir: "./pb_data",
})

// Add custom hooks before wrapping
pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
    // Custom initialization
    return e.Next()
})

srv := core.New(core.WithPocketbase(pb))
Location: core/server/server_options.go:35
Cannot be used with WithConfig. If a config is already set, this option will panic with ErrConfigurationConflict.
If you enable developer mode via InDeveloperMode() but the provided PocketBase instance was created in production mode, a warning will be logged and the mode will not be changed.

WithMode

Sets the developer mode flag programmatically.
func WithMode(developerMode bool) Option
Parameters:
developerMode
bool
required
  • true: Enable developer mode (auto-migrations, debug endpoints, verbose logging)
  • false: Production mode (migrations disabled, minimal logging)
Example:
import (
    "flag"
    "github.com/magooney-loon/pb-ext/core"
)

devMode := flag.Bool("dev", false, "Enable developer mode")
flag.Parse()

srv := core.New(core.WithMode(*devMode))
Location: core/server/server_options.go:46

InDeveloperMode

Convenience function to enable developer mode (equivalent to WithMode(true)).
func InDeveloperMode() Option
Example:
import "github.com/magooney-loon/pb-ext/core"

srv := core.New(core.InDeveloperMode())
// Outputs: 🔧 Developer mode
Location: core/server/server_options.go:53 Side Effects:
  • Logs "🔧 Developer mode" to stdout
  • Enables PocketBase auto-migrations
  • Enables debug endpoints

InNormalMode

Convenience function to explicitly disable developer mode (equivalent to WithMode(false)).
func InNormalMode() Option
Example:
import "github.com/magooney-loon/pb-ext/core"

srv := core.New(core.InNormalMode())
// Outputs: 🚀 Production mode
Location: core/server/server_options.go:61 Side Effects:
  • Logs "🚀 Production mode" to stdout
  • Disables PocketBase auto-migrations
  • Disables debug endpoints

Configuration Patterns

Pattern 1: Developer Mode Toggle

func main() {
    devMode := flag.Bool("dev", false, "Run in developer mode")
    flag.Parse()
    
    var opts []core.Option
    if *devMode {
        opts = append(opts, core.InDeveloperMode())
    } else {
        opts = append(opts, core.InNormalMode())
    }
    
    srv := core.New(opts...)
    srv.Start()
}

Pattern 2: Custom Data Directory

func main() {
    config := &pocketbase.Config{
        DefaultDataDir: "./custom_pb_data",
    }
    
    srv := core.New(
        core.WithConfig(config),
        core.InDeveloperMode(),
    )
    
    srv.Start()
}

Pattern 3: Shared PocketBase Instance

func main() {
    // Initialize PocketBase with custom hooks
    pb := pocketbase.New()
    
    pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
        // Custom early initialization
        return e.Next()
    })
    
    // Wrap with pb-ext
    srv := core.New(core.WithPocketbase(pb))
    
    srv.Start()
}

Pattern 4: Environment-Based Configuration

func main() {
    env := os.Getenv("ENV")
    
    var opts []core.Option
    
    switch env {
    case "development":
        opts = append(opts, core.InDeveloperMode())
        opts = append(opts, core.WithConfig(&pocketbase.Config{
            DefaultDataDir: "./dev_data",
            DefaultDebug:   true,
        }))
    case "staging":
        opts = append(opts, core.InNormalMode())
        opts = append(opts, core.WithConfig(&pocketbase.Config{
            DefaultDataDir: "./staging_data",
        }))
    case "production":
        opts = append(opts, core.InNormalMode())
        opts = append(opts, core.WithConfig(&pocketbase.Config{
            DefaultDataDir: "/var/lib/pb_data",
        }))
    }
    
    srv := core.New(opts...)
    srv.Start()
}

Error Handling

ErrConfigurationConflict

Panic error raised when both WithConfig and WithPocketbase are used together.
var ErrConfigurationConflict = errors.New(
    "WithConfig cannot be used together with WithPocketbase, cause second contains already initialized pocketbase.Config instance. Just pass your config into pocketbase.NewWithConfig func, that's enough.",
)
Location: core/server/server_options.go:18 Example Error:
pb := pocketbase.New()
config := &pocketbase.Config{DefaultDev: true}

// This will panic!
srv := core.New(
    core.WithConfig(config),
    core.WithPocketbase(pb),  // Conflict!
)
Solution:
// Option A: Configure PocketBase before wrapping
pb := pocketbase.NewWithConfig(pocketbase.Config{
    DefaultDev: true,
})
srv := core.New(core.WithPocketbase(pb))

// Option B: Use WithConfig only
srv := core.New(core.WithConfig(&pocketbase.Config{
    DefaultDev: true,
}))

Order of Operations

Options are applied in the order they are passed to New(). Later options override earlier ones:
// developerMode will be true (last wins)
srv := core.New(
    core.InNormalMode(),      // Sets developerMode = false
    core.InDeveloperMode(),   // Sets developerMode = true
)
While you can pass multiple mode options, it’s clearer to use only one. The last option always takes precedence.

See Also