Collection and schema design for PocketBase. Use when creating collections, designing schemas, adding fields, setting up relations, or choosing between base/auth/view collection types. Prevents wrong field types, documents zero-default behavior, and covers relation cascading.
Scanned 5/29/2026
Install to Claude Code
npx -y skills add davila7/claude-code-templates --skill pb-collections --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Pb Collections?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/davila7-pb-collections)More formats (shields.io, HTML) on the badges page.
---
name: "PocketBase Collections"
description: "Collection and schema design for PocketBase. Use when creating collections, designing schemas, adding fields, setting up relations, or choosing between base/auth/view collection types. Prevents wrong field types, documents zero-default behavior, and covers relation cascading."
---
# PocketBase Collection & Schema Design
## Collection Types
### Base Collection
Standard data collection. System fields: `id`, `created`, `updated`.
### Auth Collection
Extends base with authentication. Additional system fields: `email`, `emailVisibility`, `verified`, `password`, `tokenKey`.
Cannot delete system fields. Can disable email/password auth in collection options.
### View Collection
Read-only, backed by a SQL SELECT query. No create/update/delete. Fields are auto-detected from the query. Useful for aggregations, joins, and computed views.
```sql
-- Example: view collection query
SELECT p.id, p.title, COUNT(c.id) as comments_count
FROM posts p LEFT JOIN comments c ON c.post = p.id
GROUP BY p.id
```
View collections support API rules (list/view only) and can be used in relations.
## Field Types
| Type | Go type | Zero default | Notes |
|------|---------|-------------|-------|
| `text` | `string` | `""` | min/max length, regex pattern |
| `editor` | `string` | `""` | Rich text (sanitized HTML) |
| `number` | `float64` | `0` | min/max, `noDecimal` option |
| `bool` | `bool` | `false` | |
| `email` | `string` | `""` | Auto-validated format |
| `url` | `string` | `""` | Auto-validated format |
| `date` | `string` | `""` | ISO 8601 (`2024-01-01 00:00:00.000Z`) |
| `select` | `string`/`[]string` | `""`/`[]` | `values` list, `maxSelect` |
| `file` | `string`/`[]string` | `""`/`[]` | `maxSelect`, `maxSize`, `mimeTypes` |
| `relation` | `string`/`[]string` | `""`/`[]` | `collectionId`, `cascadeDelete`, `maxSelect` |
| `json` | `any` | `null` | Only type that can be null! `maxSize` |
| `autodate` | `string` | auto | `onCreate`/`onUpdate` modifiers |
| `password` | `string` | `""` | Stored hashed, never returned in API |
**Critical**: all types default to their zero value, NOT null. Only `json` fields can be null.
## Field Modifiers
Use in collection schema definitions:
- **`required`** — field cannot be empty/zero
- **`unique`** — unique constraint (composite via unique indexes)
- **`presentable`** — included in relation display
- **`hidden`** — excluded from API responses unless explicitly requested
- **`:autogenerate`** — for `text` fields: auto-generate value (e.g., slug from other field)
## Relation Patterns
### One-to-many
```
posts.author -> users (maxSelect: 1)
```
Each post has one author. Query posts by author: `author = "USER_ID"`.
### Many-to-many
```
posts.tags -> tags (maxSelect: 0, meaning unlimited)
```
Multi-select relation. Filter: `tags ?= "TAG_ID"` (contains).
### Back-relations
No explicit back-relation field needed. Use `@collection.posts.author` in API rules or expand from either side:
```
GET /api/collections/users/records/USER_ID?expand=posts_via_author
```
### Cascade Delete
Set `cascadeDelete: true` on the relation field. When the referenced record is deleted, all records pointing to it are also deleted. Default is `false` (sets to empty string).
### Self-referencing
A collection can reference itself:
```
categories.parent -> categories (maxSelect: 1)
```
## Indexes
- Created in the collection settings (not field-level)
- Format: `CREATE [UNIQUE] INDEX idx_name ON collection (field1, field2)`
- Unique indexes enforce composite uniqueness
- Partial indexes: `CREATE INDEX ... WHERE condition`
- Indexes on relation fields improve join performance
## Auth Collection Specifics
### OAuth2
Enable per-provider in collection settings. Each provider needs client ID + secret. PocketBase handles the full OAuth2 flow.
### OTP (One-Time Password)
Enable in auth collection settings. Sends code via email. Configure `otp.enabled`, `otp.duration`, `otp.length`.
### MFA (Multi-Factor Authentication)
Enable in auth collection settings. Requires a second factor after primary auth. `mfa.enabled`, `mfa.duration`, `mfa.rule` (filter to determine which users need MFA).
### Password Auth
Enabled by default. Can customize `minPasswordLength`. Can disable entirely if using only OAuth2/OTP.
### Auth Options
- `authToken.duration` — token lifetime (seconds)
- `passwordAuth.enabled` — toggle email/password
- `passwordAuth.identityFields` — fields used for login (default: `email`; can add `username`)
- `oauth2.enabled` — toggle OAuth2
- `otp.enabled` — toggle OTP
## Best Practices
1. **Prefer `select` over `bool`** when there might be more than 2 states in the future
2. **Use `relation` not `text`** for foreign keys — you get cascade, expand, and type safety
3. **`json` fields** are schemaless — use sparingly, prefer typed fields
4. **Name collections** in lowercase snake_case (e.g., `blog_posts`, `user_profiles`)
5. **Index early** — add indexes for any field used in filters or sorts
6. **`maxSelect: 1`** on relations returns a string ID; **`maxSelect: >1` or `0`** returns an array
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!