Files
2026-07-12 10:17:17 -04:00

3.5 KiB

Adding Fields to an Existing PocketBase Collection

PocketBase silently drops fields not in the collection schema — no HTTP error, no warning, just data loss. If your app writes fields that PocketBase ignores, you need to add them to the schema.

Detection

Signs that PocketBase is dropping fields:

  • Code writes a field (e.g., recommendation, explanation) via addDoc() or updateDoc()
  • The record is created/updated with HTTP 200
  • But re-reading the record shows the field as undefined/missing
  • The field works fine in Firestore but not PocketBase

Fix: PATCH the Collection Schema

Adding fields requires sending the COMPLETE fields array (existing + new) via PATCH:

#!/usr/bin/env python3
"""Add fields to existing PocketBase collection"""
import json, urllib.request, ssl

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

BASE = "http://localhost:8091"
COLLECTION_ID = "pbc_863811952"  # from GET /api/collections

# Step 1: Auth as superuser
auth_resp = json.loads(urllib.request.urlopen(
    urllib.request.Request(f"{BASE}/api/collections/_superusers/auth-with-password",
        data=json.dumps({"identity": "admin@example.com", "password": "..."}).encode(),
        headers={"Content-Type": "application/json"},
        method="POST"), context=ctx).read())
token = auth_resp["token"]

# Step 2: Get current fields
collections = json.loads(urllib.request.urlopen(
    urllib.request.Request(f"{BASE}/api/collections",
        headers={"Authorization": f"Bearer {token}"}), context=ctx).read())
svc = next(c for c in collections["items"] if c["id"] == COLLECTION_ID)
existing_fields = svc["fields"]

# Step 3: Build new fields to add
new_fields = [
    {"autogeneratePattern":"","hidden":False,"id":"text_new_1","max":0,"min":0,
     "name":"explanation","pattern":"","presentable":False,"primaryKey":False,
     "required":False,"system":False,"type":"text"},
    {"autogeneratePattern":"","hidden":False,"id":"text_new_2","max":0,"min":0,
     "name":"recommendation","pattern":"","presentable":False,"primaryKey":False,
     "required":False,"system":False,"type":"text"},
]

# Step 4: PATCH with complete fields array (existing + new)
all_fields = existing_fields + new_fields
result = json.loads(urllib.request.urlopen(
    urllib.request.Request(f"{BASE}/api/collections/{COLLECTION_ID}",
        data=json.dumps({"fields": all_fields}).encode(),
        headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
        method="PATCH"), context=ctx).read())
print(f"Updated fields: {[f['name'] for f in result['fields']]}")

Critical Requirements

  1. Send ALL fields, not just new ones. PATCH replaces the entire fields array. Sending only the new fields will DELETE all existing fields and break the collection.

  2. Each field needs a unique id string. Use descriptive strings like text_exp_001 — they just need to be unique within the collection.

  3. Field types matter. text for strings, number for numbers, bool for booleans. Use text for most fields to be safe.

  4. No system:true for custom fields. Only the built-in id field should have system:true.

Never Do This

  • Never edit the SQLite database directly. Use the REST API. Direct SQLite edits can corrupt field ID tracking and break the collection irreversibly.
  • Never use POST to update an existing collection. POST creates a new collection; PATCH updates an existing one.
  • Don't forget to include the id field. The system id field must remain in the array.