This repository demonstrates a scalable architecture for PocketBase using LibSQL and sqld for distributed database replication and load balancing.
This PoC showcases how to horizontally scale PocketBase by leveraging LibSQL's distributed database capabilities. The architecture implements a primary-replica pattern with multiple PocketBase instances connected to replicated databases, all fronted by a load balancer.
flowchart TD
A["Primary DB On Edge/Server"] --> B("Replicate DB 1 in Pocketbase VM")
A --> C("Replicate DB 2 in Pocketbase VM")
A --> D("Replicate DB n... in Pocketbase VM")
B --> E("Pocketbase Instance 1 -> N")
C --> H("Pocketbase Instance 1 -> N")
D --> K("Pocketbase Instance 1 -> N")
O[pb_hooks]
E --> O
H --> O
K --> O
F[pb_migrations]
E --> F
H --> F
K --> F
S["Load Balancer<br/>(Nginx or your choice)"]
E --> S
H --> S
K --> S
G[pb_public]
E --> G
H --> G
K --> G
T[S3 or pb_storage]
E --> T
H --> T
K --> T
S --> P["Client 1"]
S --> Q["Client 2"]
S --> R["Client n..."]
- LibSQL Primary Database: The authoritative source of truth running on sqld
- LibSQL Replica Databases: Read replicas that synchronize with the primary
- PocketBase Instances: Multiple PocketBase servers connecting to replica databases
- Load Balancer: Nginx distributing traffic across PocketBase instances
- pb_hooks: Shared custom hooks for PocketBase
- pb_public: Shared public files for PocketBase
- pb_migrations: Shared migrations for PocketBase
- MinIO S3: Object storage for file uploads and static assets
This PoC leverages LibSQL's distributed architecture as described in the LibSQL Design Document.
- SQLite Compatibility: Full compatibility with SQLite APIs and ecosystem
- Distributed Replication: Built-in primary-replica replication
- Edge Computing: Optimized for edge deployments with low latency
- ACID Transactions: Maintains ACID properties across distributed nodes
- Conflict Resolution: Automatic handling of replication conflicts
- HTTP API: RESTful interface for database operations
- Replication Protocol: Efficient primary-replica synchronization
- Multi-tenancy: Support for multiple databases per instance
- SSE Support: Server-Sent Events for real-time data streaming
Service | Port | Description |
---|---|---|
nginx | 8089 | Load balancer (main entry point) |
pocketbase1 | 8090 | PocketBase instance 1 (direct access) |
pocketbase2 | 8091 | PocketBase instance 2 (direct access) |
sqld.primary | 8080, 5001 | Primary LibSQL database |
sqld.replica1 | 8081, 5002 | LibSQL replica 1 |
sqld.replica2 | 8082, 5003 | LibSQL replica 2 |
s3.minio | 9000, 9001 | MinIO S3-compatible storage |
- Docker and Docker Compose
- Git
-
Clone the repository
git clone <your-repo-url> cd pocketbase-turso
-
Create required directories
mkdir -p data/libsql/{primary,replica1,replica2} mkdir -p data/minio mkdir -p pb_data_1 pb_data_2 mkdir -p pb_storage mkdir -p pb_hooks mkdir -p pb_public mkdir -p pb_migrations mkdir -p conf
-
Set environment variables (optional)
export DB_AUTH_TOKEN=your_secure_token_here
Or create a
.env
file:DB_AUTH_TOKEN=your_secure_token_here
-
Start all services
docker-compose up -d
-
Verify the setup
# Check all services are running docker-compose ps # Test the load balancer curl http://localhost:8089/api/health
- PocketBase (Load Balanced): http://localhost:8089
- PocketBase Admin: http://localhost:8089/\_/
- MinIO Console: http://localhost:9001 (admin:admin123)
- LibSQL Primary: http://localhost:8080
- Individual PocketBase Instances:
- http://localhost:8090 (instance 1)
- http://localhost:8091 (instance 2)
The PocketBase instances connect to LibSQL replicas using HTTP protocol:
- PocketBase 1 →
sqld.replica1:8080
- PocketBase 2 →
sqld.replica2:8080
Nginx uses round-robin load balancing by default. The configuration supports:
- WebSocket connections for real-time features
- Proper header forwarding for client identification
- Health check capabilities
- Session affinity (can be configured)
To add more instances:
-
Add a new replica in
docker-compose.yml
:sqld.replica3: image: ghcr.io/tursodatabase/libsql-server:latest depends_on: - sqld.primary platform: linux/amd64 ports: - "8083:8080" - "5004:5001" environment: - SQLD_NODE=replica - SQLD_PRIMARY_URL=libsql://sqld.primary:5001 volumes: - ./data/libsql/replica3:/var/lib/sqld
-
Add a new PocketBase instance:
pocketbase3: build: context: . dockerfile: Dockerfile args: DB_PATH: http://sqld.replica3:8080 DB_AUTH_TOKEN: ${DB_AUTH_TOKEN:-} ports: - "8092:8080" depends_on: - sqld.replica3 volumes: - ./pb_data_3:/app/pb_data - ./pb_storage:/app/pb_data/storage # Comment this if you want to use the S3 storage - ./pb_hooks:/app/pb_hooks - ./pb_public:/app/pb_public - ./pb_migrations:/app/pb_migrations restart: unless-stopped
-
Update nginx configuration to include the new instance:
upstream pocketbase_backend { server pocketbase1:8080; server pocketbase2:8080; server pocketbase3:8080; }
The custom Dockerfile builds a PocketBase binary with LibSQL support:
docker build -t pocketbase-libsql .
DB_PATH
: LibSQL database connection URLDB_AUTH_TOKEN
: Authentication token for LibSQL (optional)
Monitor the services using:
# View logs
docker-compose logs -f
# Check specific service
docker-compose logs pocketbase1
# Monitor resource usage
docker stats
- LibSQL Data:
./data/libsql/{primary,replica1,replica2}
- PocketBase Data:
./pb_data_1
,./pb_data_2
- PocketBase Storage:
./pb_storage
(Not applicable if you use the S3 storage) - MinIO Data:
./data/minio
- Database Replication: Automatic failover to healthy replicas
- Load Balancing: Traffic distribution across healthy PocketBase instances
- Health Checks: Automatic service health monitoring
- Restart Policies: Automatic container restart on failure
- Data Persistence: Persistent volumes for data durability
- Read Scaling: Multiple replicas handle read-heavy workloads
- Geographic Distribution: Deploy replicas closer to users
- Connection Pooling: Efficient database connection management
- Caching: Leverage PocketBase's built-in caching mechanisms
-
Connection refused errors
# Check if all services are running docker-compose ps # Restart failed services docker-compose restart <service-name>
-
Database synchronization issues
# Check replica status curl http://localhost:8081/v1/health curl http://localhost:8082/v1/health
-
Load balancer not working
# Test individual instances curl http://localhost:8090/api/health curl http://localhost:8091/api/health # Check nginx logs docker-compose logs nginx
# View all logs
docker-compose logs
# Follow specific service logs
docker-compose logs -f pocketbase1
docker-compose logs -f sqld.primary
docker-compose logs -f nginx
For production deployments, consider:
- Security: Use proper authentication tokens and TLS certificates
- Monitoring: Implement comprehensive monitoring and alerting
- Backup: Regular database backups and disaster recovery plans
- Scaling: Use container orchestration platforms (Kubernetes, Docker Swarm)
- Load Testing: Validate performance under expected load
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.