Pocketbase: Perfect CMS for personal projects

Pocketbase: Perfect CMS for personal projects

Recently, I was exploring different alternatives for Firebase, like Supabase, Appwrite, nHost but easy to use and self-hosted easily I found Pocketbase. A single executable backend is written in Golang. It uses sqlite3 as a database integrated with Pocketbase with a cloud-hosted version. I decided to try it out and deploy my own pocketbase instance and build a simple project with it as it also provides a js SDK.

Deploying in Fly.io

After Heroku free tier was discontinued, I started hunting for new PaaS solutions and I found a quite few of them like Fly.io. Railway, Deta, etc. Fly.io is one which stood out specifically because it provides cloud builders for containers.

I write a simple Dockerfile which can be used to deploy pocketbase.

FROM alpine:latest

ARG PB_VERSION=0.8.0

RUN apk add --no-cache \
    unzip \
    # this is needed only if you want to use scp to copy later your pb_data locally
    openssh

# download and unzip PocketBase
ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip
RUN unzip /tmp/pb.zip -d /pb/

EXPOSE 8080

# start PocketBase
CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8080"]

Steps in Dockerfile:

  1. Use alpine as a base image and assign Pocketbase version as an argument.

  2. Download and install unzip and OpenSSH

  3. Download and extract pocketbase

  4. Start pocketbase at port 8080

I also need fly.toml file to deploy this image and tell fly services what to do with this image:

# fly.toml file generated for pocketbase-darklord on 2022-11-23T14:59:24+05:30

app = "<your project name>"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[mounts]
  destination = "/pb/pb_data"
  source = "pb_data"

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

You can generate fly.toml using fly launch to create this config file and you need to add 2 things, first, where should SQLite database will be stored and ports to expose from container.

[mounts]
  destination = "/pb/pb_data"
  source = "pb_data"

All sqlite data will be store in pb_data which is also default for pocketbase.

[[services]]
  http_checks = []
  internal_port = 8080 <----
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

Port 8080 need to be exposed as we mentioned in Dockerfile.

Fly provides ephemeral storage when the container runs but for this, we need persistence storage which is provided by Fly itself. They provide 1GB of volume for free and can be added to any app be it a service or a database.

To create a volume run following:

flyctl volumes create pb_data --size=1

The name of this volume is used in the mounts portion of fly.toml file.

Run fly deploy to deploy your app. When this is completed you can access pocketbase with <project_name>.fly.io URL.

First, run

After deployment, it asked me to create an admin user and log in. I created a few tables which are called collections here and create a react native expo project to track technologies I want to keep track of.

Integration with JS SDK

When using JS SDK in react native it reminded me of Firebase when I first started using it.

Install using npm

npm install --save pocketbase

Create a client and then make requests

import PocketBase from 'pocketbase';

const pb = new PocketBase('<your pocketbase url>');

// this returns all list of techs from table
const result = await pb.collection('techs').getList(1, 20);

// this returns a single record
const tech = await pb.collection('techs').getOne(1);

The best part about pocketbase is it provides SDK and API examples right in the admin panel.

Also, there are controls to manage how these data can be accessed and which operations are permitted.

Pocketbase also provides a real-time API which is SSE (Server Side Events) and subscribe() the method in its JS SDK. Did I tell you it also provides Dart SDK to work with Flutter.

Pocketbase being pocket size provides so many solutions out-of-box like mail, authentication using email/password, OAuth, and file storage which can be extended using S3 object storage.

It also provides logs for your api requests.

Do try out pocketbase. Hope you love it!

Did you find this article valuable?

Support Ratnadeep Bhattacharyya by becoming a sponsor. Any amount is appreciated!