# 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: ```python #!/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.