跳转至

578_PocketBase轻量后端

一句话概述:PocketBase 是一个用 Go 编写的开源后端,把数据库(SQLite)、认证、文件存储、管理面板和 REST API 全部打包进一个可执行文件,下载即用,是个人项目和 MVP 的神器。

核心知识点表

概念白话解释
单文件后端整个后端就一个文件,双击运行就有了数据库+API+管理面板
SQLite WALSQLite 的预写日志模式,读性能比 MySQL 还快
CollectionPocketBase 里的"表",在管理面板点击创建,自动生成 API
RecordCollection 里的一条数据,相当于数据库里的一行
Auth Collection特殊的 Collection,自带用户注册登录功能
Realtime实时订阅,数据变化时自动推送到前端(WebSocket)
Hook钩子,在数据创建/更新/删除前后执行自定义逻辑

安装配置

下载安装

# 方法1:直接下载可执行文件(推荐)
# 访问 https://pocketbase.io/docs/ 下载对应平台的包
wget https://github.com/pocketbase/pocketbase/releases/download/v0.25.0/pocketbase_0.25.0_linux_amd64.zip
unzip pocketbase_0.25.0_linux_amd64.zip  # 解压得到 pocketbase 可执行文件

# 方法2:用 Go 安装(需要 Go 1.23+)
go install github.com/pocketbase/pocketbase@latest

启动服务

./pocketbase serve                   # 启动服务,默认监听 127.0.0.1:8090
./pocketbase serve --http="0.0.0.0:8090"  # 允许外部访问

# 启动后会创建两个重要文件:
# pb_data/          → 数据库文件和上传文件的存储目录
# pb_data/data.db   → SQLite 数据库文件(所有数据都在这里)

访问管理面板

# 管理面板地址:http://127.0.0.1:8090/_/
# API 地址:     http://127.0.0.1:8090/api/

# 首次访问管理面板需要创建管理员账号

Docker 部署

# docker-compose.yml
services:
  pocketbase:
    image: ghcr.io/muchobien/pocketbase:latest  # 社区维护的镜像
    container_name: pocketbase                    # 容器名
    restart: unless-stopped                       # 自动重启
    ports:
      - "8090:8090"                               # 映射端口
    volumes:
      - ./pb_data:/pb_data                        # 持久化数据
      - ./pb_migrations:/pb_migrations            # 持久化迁移文件
docker compose up -d                 # 启动
docker compose logs -f pocketbase    # 查看日志

基本使用

创建 Collection(管理面板操作)

# 在管理面板 http://localhost:8090/_/ 操作:
# 1. 点击 "New collection"
# 2. 输入名称,如 "posts"
# 3. 添加字段:
#    - title (Plain text, Required)
#    - content (Editor/Rich text)
#    - published (Bool)
#    - cover (File, 单文件)
# 4. 设置 API 权则(谁能增删改查)
# 5. 保存 → 自动生成 REST API

JavaScript SDK 使用

// 安装 SDK
// npm install pocketbase

import PocketBase from 'pocketbase';             // 导入 SDK

const pb = new PocketBase('http://127.0.0.1:8090'); // 连接 PocketBase

// === 用户认证 ===
// 注册新用户
const user = await pb.collection('users').create({
    email: 'test@example.com',                    // 邮箱
    password: '12345678',                         // 密码(最少8位)
    passwordConfirm: '12345678',                  // 确认密码
    name: '张三'                                   // 用户名
});

// 登录
const authData = await pb.collection('users').authWithPassword(
    'test@example.com',                           // 邮箱
    '12345678'                                    // 密码
);
console.log(pb.authStore.isValid);                // true = 登录成功
console.log(pb.authStore.token);                  // JWT token

// === CRUD 操作 ===
// 创建记录
const post = await pb.collection('posts').create({
    title: '我的第一篇文章',                        // 标题
    content: '这是内容...',                         // 内容
    published: true                                // 是否发布
});

// 查询列表(分页)
const list = await pb.collection('posts').getList(
    1,                                             // 第1页
    20,                                            // 每页20条
    { filter: 'published = true' }                 // 筛选条件
);
console.log(list.items);                           // 文章数组

// 查询单条
const record = await pb.collection('posts').getOne('RECORD_ID');

// 更新记录
await pb.collection('posts').update('RECORD_ID', {
    title: '修改后的标题'
});

// 删除记录
await pb.collection('posts').delete('RECORD_ID');

文件上传

// 创建带文件的记录
const formData = new FormData();                  // 创建表单数据
formData.append('title', '带图片的文章');           // 添加文本字段
formData.append('cover', fileInput.files[0]);     // 添加文件字段

const record = await pb.collection('posts').create(formData);

// 获取文件 URL
const url = pb.files.getURL(record, record.cover); // 获取完整文件地址
console.log(url);  // http://127.0.0.1:8090/api/files/posts/xxx/cover.jpg

高级用法

实时订阅(Realtime)

// 订阅某个 collection 的所有变化
pb.collection('posts').subscribe('*', (e) => {
    console.log('事件类型:', e.action);             // create / update / delete
    console.log('变化的数据:', e.record);            // 完整记录
});

// 订阅单条记录的变化
pb.collection('posts').subscribe('RECORD_ID', (e) => {
    console.log('这条记录变了:', e.record);
});

// 取消订阅
pb.collection('posts').unsubscribe('*');           // 取消全部订阅
pb.collection('posts').unsubscribe('RECORD_ID');   // 取消单条订阅

Go 扩展(自定义后端逻辑)

package main

import (
    "log"
    "github.com/pocketbase/pocketbase"            // 导入 PocketBase
    "github.com/pocketbase/pocketbase/core"
)

func main() {
    app := pocketbase.New()                        // 创建 PocketBase 实例

    // 注册自定义 API 路由
    app.OnServe().BindFunc(func(se *core.ServeEvent) error {
        se.Router.GET("/api/hello", func(e *core.RequestEvent) error {
            return e.JSON(200, map[string]string{  // 返回 JSON
                "message": "Hello from custom API!",
            })
        })
        return se.Next()
    })

    // 注册钩子:创建记录前执行
    app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error {
        log.Println("即将创建文章:", e.Record.GetString("title"))
        return e.Next()                            // 继续执行
    })

    if err := app.Start(); err != nil {            // 启动服务
        log.Fatal(err)
    }
}
# 编译运行自定义后端
go mod init myapp                    # 初始化 Go 模块
go mod tidy                          # 下载依赖
go build -o myapp .                  # 编译
./myapp serve                        # 启动

过滤与排序语法

// PocketBase 使用自己的过滤语法
const results = await pb.collection('posts').getList(1, 20, {
    filter: 'published = true && created > "2024-01-01"',  // AND 过滤
    sort: '-created,title',                                 // 按创建时间倒序,标题正序
    expand: 'author',                                       // 展开关联字段
    fields: 'id,title,created'                              // 只返回指定字段
});

数据备份

# 方法1:直接复制数据目录
cp -r pb_data/ pb_data_backup_$(date +%Y%m%d)/

# 方法2:使用 SQLite 命令备份
sqlite3 pb_data/data.db ".backup pb_data/backup.db"

# 方法3:管理面板 → Settings → Backups → Create backup

常见报错

报错信息原因解决方案
Failed to initialize the DB数据库文件损坏或权限不足检查 pb_data 目录权限
API rule errorCollection 的 API 权限未配置在管理面板设置 API Rules
400 Validation error必填字段未提供或格式错误检查请求数据是否符合字段规则
403 Forbidden未登录或无权限先调用 authWithPassword 登录
Port already in use8090端口被占用改用 --http="0.0.0.0:8091"
NFS not supported数据目录在网络文件系统上SQLite 不支持 NFS,使用本地磁盘

速查表

# === PocketBase 命令 ===
./pocketbase serve                   # 启动服务
./pocketbase serve --http="0.0.0.0:8090"  # 允许外网访问
./pocketbase migrate                 # 执行迁移
./pocketbase admin create email pass # 创建管理员
./pocketbase admin update email pass # 更新管理员密码
./pocketbase update                  # 自动更新到最新版

# === API 端点 ===
# POST   /api/collections/{name}/records     # 创建记录
# GET    /api/collections/{name}/records     # 查询列表
# GET    /api/collections/{name}/records/:id # 查询单条
# PATCH  /api/collections/{name}/records/:id # 更新记录
# DELETE /api/collections/{name}/records/:id # 删除记录
# POST   /api/collections/users/auth-with-password  # 登录

# === 过滤语法 ===
# =    等于           title = "hello"
# !=   不等于         status != "draft"
# >    大于           age > 18
# >=   大于等于       score >= 60
# <    小于           price < 100
# ~    包含(like)     title ~ "关键词"
# &&   AND            a = 1 && b = 2
# ||   OR             a = 1 || b = 2

同类对比

特性PocketBaseAppwriteSupabaseFirebase
部署方式单文件Docker 20+容器Docker云服务
数据库SQLiteMariaDBPostgreSQLFirestore
内存需求~50MB4GB+2GB+N/A
实时功能支持支持支持支持
扩展方式Go/JS代码云函数Edge FunctionsCloud Functions
适合规模小型/MVP中大型中大型任意
开源协议MITMITApache 2.0闭源
横向扩展不支持支持支持支持

选型建议:个人项目、MVP、小团队首选 PocketBase(零依赖、秒部署);需要横向扩展的中大型项目选 Appwrite 或 Supabase。PocketBase 当前仍在 v1.0 前,API 可能有变动。