PocketBase is an open-source backend that comes as a single executable file. It includes a database (SQLite), authentication, file storage, and real-time subscriptions — all in one 15MB binary.
Why PocketBase Matters
Setting up a backend typically means: database server, auth service, file storage, API framework, and deployment configs. PocketBase replaces ALL of it with one file you can run anywhere.
What you get for free:
- RESTful API auto-generated from your schema
- Real-time subscriptions via SSE
- Built-in authentication (email, OAuth2)
- File storage with thumbnails
- Admin dashboard UI
- Single executable, zero dependencies
- SQLite database (embedded)
- Go and JavaScript/Dart SDKs
Quick Start
# Download single binary
wget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip
unzip pocketbase_linux_amd64.zip
# Run (that is literally it)
./pocketbase serve
# Admin UI: http://127.0.0.1:8090/_/
# API: http://127.0.0.1:8090/api/
JavaScript SDK
import PocketBase from "pocketbase";
const pb = new PocketBase("http://127.0.0.1:8090");
// Authentication
await pb.collection("users").authWithPassword("user@example.com", "password123");
// Create record
const post = await pb.collection("posts").create({
title: "Hello PocketBase",
content: "This is my first post",
author: pb.authStore.model.id,
});
// List with filtering
const posts = await pb.collection("posts").getList(1, 20, {
filter: 'created >= "2024-01-01"',
sort: "-created",
expand: "author",
});
// Real-time subscriptions
pb.collection("posts").subscribe("*", (e) => {
console.log(e.action); // create, update, delete
console.log(e.record);
});
// File upload
const formData = new FormData();
formData.append("title", "Photo Post");
formData.append("image", fileInput.files[0]);
const record = await pb.collection("posts").create(formData);
// Get file URL
const url = pb.files.getURL(record, record.image);
React Integration
import { useEffect, useState } from "react";
import PocketBase from "pocketbase";
const pb = new PocketBase("http://127.0.0.1:8090");
function PostList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
// Load initial data
pb.collection("posts").getFullList({ sort: "-created" })
.then(setPosts);
// Subscribe to changes
pb.collection("posts").subscribe("*", (e) => {
if (e.action === "create") {
setPosts((prev) => [e.record, ...prev]);
}
});
return () => pb.collection("posts").unsubscribe();
}, []);
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Extend with Go
package main
import (
"log"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
// Add custom route
app.OnServe().BindFunc(func(se *core.ServeEvent) error {
se.Router.GET("/api/custom/stats", func(e *core.RequestEvent) error {
records, _ := app.FindAllRecords("posts")
return e.JSON(200, map[string]int{"total": len(records)})
})
return se.Next()
})
// Hook: before create
app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error {
e.Record.Set("slug", slugify(e.Record.GetString("title")))
return e.Next()
})
log.Fatal(app.Start())
}
Deployment
# It is literally one file. Deploy anywhere:
scp pocketbase user@server:/opt/pocketbase/
ssh user@server '/opt/pocketbase/pocketbase serve --http=0.0.0.0:8090'
# Or Docker
FROM alpine:latest
COPY pocketbase /usr/local/bin/
EXPOSE 8090
CMD ["pocketbase", "serve", "--http=0.0.0.0:8090"]
Links
Building data backends? Check out my developer tools on Apify or email spinov001@gmail.com for custom solutions.
Top comments (0)