Featured image of post PocketBase: Go's Effortless Backend Solution

PocketBase: Go's Effortless Backend Solution

PocketBase is a realtime backend in 1 file consisting of embedded database (SQLite) with realtime subscriptions, built-in auth management and much more.

PocketBase: The Single-File Backend Powerhouse for Go Developers

Introduction

PocketBase is a revolutionary Go library that packages an entire backend system into a single executable file, boasting 55,723 stars on GitHub at the time of writing. This embedded database solution combines SQLite with realtime capabilities, authentication, and file storage - all ready to use out of the box.

Unlike traditional backend setups that require stitching together multiple services, PocketBase gives developers:

  • A complete backend in one executable
  • Built-in user authentication
  • Realtime data subscriptions
  • Automatic REST API generation
  • File storage capabilities

Why should you care? For small-to-medium projects, prototypes, or even production microservices, PocketBase eliminates weeks of boilerplate work. It’s particularly valuable for:

  • Rapid application development
  • Serverless/edge computing deployments
  • IoT data collection systems
  • Real-time collaborative apps
  • Mobile app backends

The library shines in scenarios where you need database-powered functionality without operational complexity. Startups love it for MVP development, while enterprises use it for internal tools requiring minimal setup.

Key Features

  1. Embedded SQLite Database

    • Full ACID-compliant database in your binary
    • No external dependencies or setup required
    • Superior to file-based storage or manual SQLite management
  2. Realtime Subscriptions

    • WebSocket-powered live queries
    • More efficient than polling REST endpoints
    • Comparable to Firebase but with SQL capabilities
  3. Built-in Auth System

    • Complete user management (email/password, OAuth2)
    • Password reset flows out of the box
    • Saves months of development vs building from scratch
  4. Automatic REST API

    • CRUD endpoints auto-generated for collections
    • Supports filtering, sorting, and pagination
    • Beats manual endpoint creation with standard net/http
  5. Admin Dashboard

    • Web UI for data management
    • Comparable to Django Admin but Go-native
    • Accessible via /_/ in your deployment
  6. File Storage

    • Built-in S3-compatible storage
    • Asset management with access controls
    • No need for separate cloud storage setup
  7. Extensible Hooks

    • Middleware-like event handlers
    • Custom business logic injection points
    • More focused than generic Go middleware systems

Installation and Setup

Requirements:

  • Go 1.20+
  • CGO enabled (for SQLite)

Install the CLI tool:

1go install github.com/pocketbase/pocketbase@latest

Verify installation:

1pocketbase --version
2# Expected output: pocketbase version X.Y.Z

Create a minimal Go program:

 1package main
 2
 3import (
 4    "log"
 5    "github.com/pocketbase/pocketbase"
 6)
 7
 8func main() {
 9    app := pocketbase.New()
10    if err := app.Start(); err != nil {
11        log.Fatal(err)
12    }
13}

Run with:

1go run main.go

You should see:

1Starting PocketBase...
2 - URL: http://127.0.0.1:8090
3 - Admin UI: http://127.0.0.1:8090/_/

Basic Usage

Let’s create a simple contact management system:

 1package main
 2
 3import (
 4    "log"
 5    "github.com/pocketbase/pocketbase"
 6    "github.com/pocketbase/pocketbase/core"
 7)
 8
 9func main() {
10    app := pocketbase.New()
11
12    app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
13        // Register new route
14        e.Router.GET("/hello", func(c echo.Context) error {
15            return c.String(200, "Hello from PocketBase!")
16        })
17        return nil
18    })
19
20    if err := app.Start(); err != nil {
21        log.Fatal(err)
22    }
23}

This demonstrates:

  1. Creating a new PocketBase instance
  2. Registering a custom route
  3. Starting the server

Test with:

1curl http://localhost:8090/hello
2# Output: Hello from PocketBase!

Real-World Examples

Example 1: Todo API with Auth and Realtime Updates

 1package main
 2
 3import (
 4    "log"
 5    "github.com/pocketbase/pocketbase"
 6    "github.com/pocketbase/pocketbase/apis"
 7    "github.com/pocketbase/pocketbase/core"
 8    "github.com/pocketbase/pocketbase/models"
 9)
10
11func main() {
12    app := pocketbase.New()
13
14    // Create todos collection
15    app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
16        _, err := app.Dao().FindCollectionByNameOrId("todos")
17        if err != nil {
18            collection := &models.Collection{
19                Name:       "todos",
20                Type:       models.CollectionTypeBase,
21                ListRule:   "@request.auth.id != ''",
22                ViewRule:   "@request.auth.id != ''",
23                CreateRule: "@request.auth.id != ''",
24                Schema: models.NewSchema(
25                    &models.SchemaField{
26                        Name:     "title",
27                        Type:     models.FieldTypeText,
28                        Required: true,
29                    },
30                    &models.SchemaField{
31                        Name:     "completed",
32                        Type:     models.FieldTypeBool,
33                        Required: true,
34                        Default:  false,
35                    },
36                    &models.SchemaField{
37                        Name:     "user",
38                        Type:     models.FieldTypeRelation,
39                        Required: true,
40                        Options: &models.RelationOptions{
41                            CollectionId: "users",
42                        },
43                    },
44                ),
45            }
46
47            if err := app.Dao().SaveCollection(collection); err != nil {
48                return err
49            }
50        }
51
52        // Custom validation endpoint
53        e.Router.POST("/api/todos/validate", func(c echo.Context) error {
54            record, _ := c.Get(apis.ContextRecordKey).(*models.Record)
55            if record.GetString("title") == "invalid" {
56                return c.String(400, "Invalid todo title")
57            }
58            return c.NoContent(204)
59        }, apis.ActivityLogger(app), apis.RecordAuth())
60
61        return nil
62    })
63
64    // Realtime notifications
65    app.OnRecordAfterCreateRequest("todos").Add(func(e *core.RecordCreateEvent) error {
66        log.Printf("New todo created: %s", e.Record.Id)
67        return nil
68    })
69
70    if err := app.Start(); err != nil {
71        log.Fatal(err)
72    }
73}

This example creates:

  • A todos collection with auth rules
  • Custom validation endpoint
  • Realtime creation hooks
  • Relation to users collection

Example 2: File Upload Service with Size Limits

 1package main
 2
 3import (
 4    "log"
 5    "github.com/pocketbase/pocketbase"
 6    "github.com/pocketbase/pocketbase/core"
 7    "github.com/pocketbase/pocketbase/models"
 8)
 9
10func main() {
11    app := pocketbase.New()
12
13    app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
14        // Create files collection
15        collection := &models.Collection{
16            Name: "files",
17            Type: models.CollectionTypeBase,
18            Schema: models.NewSchema(
19                &models.SchemaField{
20                    Name:     "file",
21                    Type:     models.FieldTypeFile,
22                    Required: true,
23                    Options: &models.FileOptions{
24                        MaxSize: 10485760, // 10MB
25                    },
26                },
27            ),
28        }
29
30        if err := app.Dao().SaveCollection(collection); err != nil {
31            return err
32        }
33
34        // Add upload validation
35        app.OnFileBeforeUpload().Add(func(e *core.FileUploadEvent) error {
36            if e.File.Size > 10485760 {
37                return apis.NewBadRequestError("File too large", nil)
38            }
39            return nil
40        })
41
42        return nil
43    })
44
45    if err := app.Start(); err != nil {
46        log.Fatal(err)
47    }
48}

Features:

  • File collection with size constraints
  • Server-side validation
  • Built-in file management UI

Best Practices and Common Pitfalls

  1. Security Essentials

    • Always set collection auth rules
    • Protect admin UI with strong password
    • Use HTTPS in production
  2. Database Management

    • Implement regular SQLite backups
    • Use WAL mode for better concurrency
    • Monitor database size growth
  3. Performance Tips

    • Keep hook logic lean
    • Use indexes for frequently queried fields
    • Cache expensive operations
  4. Common Mistakes

    • Forgetting to set collection permissions
    • Not handling hook errors properly
    • Storing large binary data in records
  5. When to Avoid

    • High-write workloads (>1000 TPS)
    • Multi-region deployments
    • Complex SQL relationships

Conclusion

PocketBase revolutionizes backend development by providing a complete system in a single Go library. With its embedded database, realtime capabilities, and built-in auth, it’s perfect for:

  • Rapid prototyping
  • Small-to-medium web apps
  • Internal tools
  • Mobile app backends

While not suited for massive scale-out scenarios, it excels in situations where simplicity and speed matter most. The active community and comprehensive documentation make it easy to get started.

Resources:

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy