Skip to main content
PocketBase can be used as a Go framework, giving you complete control over the application lifecycle, custom commands, and direct access to all PocketBase internals.

Installation

First, create a new Go module and install PocketBase:
mkdir myapp
cd myapp
go mod init myapp
go get github.com/pocketbase/pocketbase

Basic example

Here’s a minimal example from examples/base/main.go:
main.go
package main

import (
    "log"
    "github.com/pocketbase/pocketbase"
)

func main() {
    app := pocketbase.New()

    if err := app.Start(); err != nil {
        log.Fatal(err)
    }
}
This creates a PocketBase instance with default settings and starts the server.

Configuration

You can customize PocketBase’s configuration using NewWithConfig:
package main

import (
    "log"
    "time"
    "github.com/pocketbase/pocketbase"
)

func main() {
    app := pocketbase.NewWithConfig(pocketbase.Config{
        DefaultDataDir:      "./pb_data",
        DefaultDev:          true,
        DefaultQueryTimeout: 30 * time.Second,
        HideStartBanner:     false,
        DataMaxOpenConns:    20,
        DataMaxIdleConns:    5,
    })

    if err := app.Start(); err != nil {
        log.Fatal(err)
    }
}
The application is bootstrapped automatically when you call app.Start(). Database connections, migrations, and settings are initialized at this point.

Application lifecycle

The PocketBase app follows this lifecycle:
1

Creation

Create a new PocketBase instance with New() or NewWithConfig().
app := pocketbase.New()
2

Configuration

Register plugins, hooks, and custom commands before starting.
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
    // Add custom routes
    return e.Next()
})
3

Bootstrap

The app bootstraps when Start() or Execute() is called. This initializes:
  • Database connections
  • Migrations
  • Application settings
  • Event hooks
4

Execution

The app executes the command (default is serve) and runs until terminated.
5

Termination

Graceful shutdown with cleanup via OnTerminate() hooks.

Custom commands

You can add custom CLI commands to your PocketBase app:
package main

import (
    "log"
    "github.com/pocketbase/pocketbase"
    "github.com/spf13/cobra"
)

func main() {
    app := pocketbase.New()

    // Add a custom command
    app.RootCmd.AddCommand(&cobra.Command{
        Use:   "hello",
        Short: "Prints a greeting message",
        Run: func(cmd *cobra.Command, args []string) {
            log.Println("Hello from custom command!")
        },
    })

    if err := app.Start(); err != nil {
        log.Fatal(err)
    }
}
Run it with:
go run main.go hello

Working with the database

app.OnServe().BindFunc(func(e *core.ServeEvent) error {
    // Find a single record
    record, err := app.FindRecordById("posts", "RECORD_ID")
    if err != nil {
        return err
    }

    // Query multiple records
    records, err := app.FindRecordsByFilter(
        "posts",
        "status = 'published'",
        "-created",
        20,
        0,
    )
    if err != nil {
        return err
    }

    return e.Next()
})

Accessing app settings

You can read and modify application settings:
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
    // Read settings
    settings := app.Settings()
    appName := settings.Meta.AppName
    
    // Modify settings
    settings.Meta.AppName = "My Custom App"
    
    // Save settings
    if err := app.Save(settings); err != nil {
        return err
    }
    
    return e.Next()
})

Register plugins

PocketBase supports a plugin system for modular extensions:
package main

import (
    "log"
    "github.com/pocketbase/pocketbase"
    "github.com/pocketbase/pocketbase/plugins/jsvm"
    "github.com/pocketbase/pocketbase/plugins/migratecmd"
)

func main() {
    app := pocketbase.New()

    // Register JavaScript VM plugin for pb_hooks
    jsvm.MustRegister(app, jsvm.Config{
        HooksDir:      "./pb_hooks",
        HooksWatch:    true,
        HooksPoolSize: 15,
    })

    // Register migration command plugin
    migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{
        TemplateLang: migratecmd.TemplateLangJS,
        Automigrate:  true,
    })

    if err := app.Start(); err != nil {
        log.Fatal(err)
    }
}

Build and deployment

1

Build the binary

CGO_ENABLED=0 go build -o myapp
2

Run the application

./myapp serve --http=0.0.0.0:8080
3

Optional: Cross-compile

# For Linux
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o myapp-linux

# For macOS
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o myapp-mac

# For Windows
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o myapp.exe
Always use CGO_ENABLED=0 when building PocketBase to ensure the binary is statically linked and portable.

Complete example

Here’s a complete example with multiple features:
main.go
package main

import (
    "log"
    "net/http"
    "os"
    
    "github.com/pocketbase/pocketbase"
    "github.com/pocketbase/pocketbase/apis"
    "github.com/pocketbase/pocketbase/core"
    "github.com/pocketbase/pocketbase/plugins/jsvm"
)

func main() {
    app := pocketbase.New()

    // Register JSVM plugin
    var hooksDir string
    app.RootCmd.PersistentFlags().StringVar(
        &hooksDir,
        "hooksDir",
        "./pb_hooks",
        "the directory with the JS hooks",
    )
    
    app.RootCmd.ParseFlags(os.Args[1:])
    
    jsvm.MustRegister(app, jsvm.Config{
        HooksDir:      hooksDir,
        HooksWatch:    true,
        HooksPoolSize: 15,
    })

    // Add custom route
    app.OnServe().BindFunc(func(e *core.ServeEvent) error {
        e.Router.GET("/api/hello", func(re *core.RequestEvent) error {
            return re.JSON(http.StatusOK, map[string]string{
                "message": "Hello, World!",
            })
        })
        
        return e.Next()
    })

    // Add record creation hook
    app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error {
        log.Printf("New post created: %s\n", e.Record.GetString("title"))
        return e.Next()
    })

    if err := app.Start(); err != nil {
        log.Fatal(err)
    }
}

Next steps

Event hooks

Learn about all available event hooks

Custom routes

Add custom API endpoints