Saltar al contenido principal

PocketBase

Backend completo en un solo archivo binario: base de datos SQLite, autenticación, almacenamiento de archivos, y API REST + Realtime. Se despliega en Fly.io gratis.

Límites del plan gratuito

PocketBase es self-hosted: tú lo desplegás en tu propio servidor. Con Fly.io gratis, los límites son los del hosting, no los del software en sí.

ParámetroValor (Fly.io free tier)
VMs1 × shared-cpu-1x (256 MB RAM)
Storage (volume)1 GB persistente gratis
Bandwidth160 GB salida/mes
Base de datosSQLite (incluida en el binario)
Auth, Realtime, Files✅ Incluido y sin límites de usuarios
Costo del softwareGratis para siempre (open source)
Sin pausas✅ (con auto_stop_machines = false)
info

A diferencia de Firebase o Supabase, PocketBase no tiene límites de MAU, reads/writes o storage en el software — los únicos límites son los del servidor donde lo hosteas.

¿Qué incluye?

CaracterísticaDisponible
Base de datos✅ SQLite
API REST auto-generada
Dashboard admin (UI)
Autenticación✅ (email/password, OAuth)
Almacenamiento de archivos
Realtime (websockets)
Extensiones en Go
Self-hosted✅ (gratis siempre)
Docker image

Despliegue en Fly.io (100% gratis)

# Prerrequisito: tener flyctl instalado y cuenta en Fly.io
fly auth login

# Crear app
fly apps create mi-pocketbase --machines

# Crear volume para persistencia de datos (1 GB gratis)
fly volumes create pb_data --app mi-pocketbase --size 1 --region mad

# Crear fly.toml

Crear archivo fly.toml:

app = "mi-pocketbase"
primary_region = "mad"

[build]
image = "ghcr.io/muchobien/pocketbase:latest"

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

[http_service]
internal_port = 8090
force_https = true
auto_stop_machines = false
auto_start_machines = true
min_machines_running = 1

[[vm]]
memory = "256mb"
cpu_kind = "shared"
cpus = 1
# Desplegar
fly deploy

# Ver URL de tu PocketBase:
fly open

# El admin panel está en: https://mi-pocketbase.fly.dev/_/

Configuración inicial

1. Ir a: https://mi-pocketbase.fly.dev/_/
2. Crear cuenta admin (solo la primera vez)
3. Explorar el dashboard

Crear colecciones (tablas)

Collections → New Collection
→ Name: productos
→ Fields:
- nombre (text, required)
- precio (number)
- descripcion (text)
- imagen (file)
- activo (bool, default: true)
→ API Rules: configurar quién puede leer/escribir
→ Save

PocketBase genera automáticamente la API REST:

GET    /api/collections/productos/records
POST /api/collections/productos/records
GET /api/collections/productos/records/:id
PATCH /api/collections/productos/records/:id
DELETE /api/collections/productos/records/:id

SDK de JavaScript

npm install pocketbase
// lib/pocketbase.ts
import PocketBase from 'pocketbase'

export const pb = new PocketBase('https://mi-pocketbase.fly.dev')

Operaciones CRUD

import { pb } from '@/lib/pocketbase'

// Listar registros
const productos = await pb.collection('productos').getList(1, 20, {
filter: 'activo = true',
sort: '-created',
expand: 'categoria' // relaciones
})
console.log(productos.items)

// Obtener uno
const producto = await pb.collection('productos').getOne('RECORD_ID')

// Buscar
const resultados = await pb.collection('productos').getList(1, 10, {
filter: `nombre ~ "${busqueda}" && precio < 100`,
})

// Crear
const nuevo = await pb.collection('productos').create({
nombre: 'Laptop',
precio: 999,
activo: true
})

// Con archivo
const formData = new FormData()
formData.append('nombre', 'Laptop')
formData.append('imagen', archivoFile)
const con_imagen = await pb.collection('productos').create(formData)

// Actualizar
const actualizado = await pb.collection('productos').update('RECORD_ID', {
precio: 899
})

// Eliminar
await pb.collection('productos').delete('RECORD_ID')

Autenticación

// Registro con email/password
const usuario = await pb.collection('users').create({
email: 'juan@email.com',
password: 'contraseña123',
passwordConfirm: 'contraseña123',
nombre: 'Juan'
})

// Login
const authData = await pb.collection('users').authWithPassword(
'juan@email.com',
'contraseña123'
)
console.log(pb.authStore.isValid) // true
console.log(pb.authStore.model) // datos del usuario
console.log(pb.authStore.token) // JWT token

// Login con OAuth (Google, GitHub, etc.)
const authData = await pb.collection('users').authWithOAuth2({
provider: 'google',
})

// Verificar sesión actual
const user = await pb.collection('users').authRefresh()

// Logout
pb.authStore.clear()

// Persistir sesión (localStorage en browser)
// PocketBase lo maneja automáticamente en browser

Realtime (suscripciones)

// Escuchar todos los cambios en una colección
pb.collection('mensajes').subscribe('*', (e) => {
console.log(e.action) // 'create', 'update', 'delete'
console.log(e.record) // datos del registro
})

// Escuchar cambios de un registro específico
pb.collection('productos').subscribe('RECORD_ID', (e) => {
console.log('Producto actualizado:', e.record)
})

// Desuscribirse
pb.collection('mensajes').unsubscribe()

API Rules (seguridad)

En el dashboard de PocketBase, configura las reglas para cada colección:

Collections → productos → API Rules

List/Search: @request.auth.id != "" ← solo usuarios autenticados
View: "" ← público
Create: @request.auth.id != "" ← autenticados
Update: @request.auth.id = @collection.usuarios.id ← solo el dueño
Delete: @request.auth.roles ?~ "admin" ← solo admins

Actualizar PocketBase

# Ver versiones disponibles
# https://github.com/pocketbase/pocketbase/releases

# Actualizar imagen en Fly.io:
# Cambiar la versión en fly.toml:
[build]
image = "ghcr.io/muchobien/pocketbase:0.22.0"

fly deploy

⚠️ Limitaciones importantes

  • SQLite: no escala bien para muchas escrituras concurrentes
  • Self-hosted: tú eres responsable de los backups
  • 1 instancia: no tiene clustering (solo 1 instancia en Fly.io free)
  • Backups manuales: hacer backups del volume de Fly.io regularmente

Hacer backup

# Descargar el archivo de base de datos
fly ssh console -a mi-pocketbase
# Dentro del contenedor:
cp /pb_data/data.db /tmp/backup.db

# O usar el endpoint de backup de PocketBase:
# GET /api/backups (requiere admin token)