Collections & API Rules
Collections are PocketBase’s tables. Each collection defines a schema (typed fields) and a set of API rules that control who can list, view, create, update, and delete its records. Getting the rules right is the single most important step in securing your app.
Creating a collection
Using the portal
- Open the admin panel at
https://<instance-name>.pocketbasecloud.com/_/ - Click New collection
- Choose the type:
- Base — regular data (posts, products, comments, …)
- Auth — user accounts with login capability
- View — read-only collection backed by a SQL
SELECT
- Add fields and click Create
Using the CLI
Point pb at the instance once, log in as its superuser, and the collection
commands work against it:
pb use https://<instance-name>.pocketbasecloud.com
pb login
Create an empty collection, or pass a full definition to create it with its fields in one step:
pb collections create tasks --type base
pb collections create '{"name":"posts","type":"base","fields":[
{"name":"title","type":"text","required":true},
{"name":"body","type":"editor"},
{"name":"published","type":"bool"}]}'
Inspect and change them:
pb collections ls
pb collections get posts
pb collections update posts '{"fields":[…]}'
pb collections rm posts
pb use --name <profile> keeps several instances side by side (staging and
production, say), and --profile <name> picks one per command. The same
commands work against a local instance — pb use http://127.0.0.1:8090.
Field types
PocketBase supports the field types you’d expect:
| Type | Use for |
|---|---|
text, editor, number, bool |
Basic values, rich text |
email, url, date |
Validated formats |
select |
One or more values from a fixed list |
relation |
References to records in another collection |
file |
File uploads |
json |
Arbitrary structured data |
Relations are expanded on demand with the expand query parameter:
const post = await pb.collection("posts").getOne("RECORD_ID", {
expand: "author,comments_via_post",
});
API rules
Each collection has five rules — List, View, Create, Update, and Delete. A rule is a filter expression; the operation is allowed only when the expression matches.
Using the portal
Edit them from the lock icon on the collection page in the admin panel.
Using the CLI
pb rules get posts
pb rules set posts \
--list-rule '@request.auth.id != ""' \
--view-rule '@request.auth.id != ""' \
--create-rule '@request.auth.id != ""' \
--update-rule 'author = @request.auth.id' \
--delete-rule 'author = @request.auth.id'
Pass null as a value to lock a rule back to superusers only:
pb rules set posts --delete-rule null
Three states matter, whichever way you set them:
- Locked (superusers only) — the rule is
null; only superusers via the admin panel or admin token can perform the operation - Empty string — anyone can perform the operation
- Filter expression — allowed only when the expression evaluates to true
Common rule recipes
Only signed-in users can read:
@request.auth.id != ""
Users can only see and edit their own records (with an owner relation
field pointing to users):
owner = @request.auth.id
Anyone can read published posts, authors see their drafts too:
status = "published" || author = @request.auth.id
Validate incoming data on create — e.g., force the owner field to the
current user:
@request.auth.id != "" && @request.body.owner = @request.auth.id
Rules can reference the current record’s fields, @request.auth (the
authenticated user), @request.body, @request.query, and even fields across
relations (author.verified = true).
Working with records
Using the portal
Open a collection in the admin panel to browse, filter, edit, and create records.
Using the CLI
The same operations, handy for seeding data and for checking what a rule actually returns:
pb records ls posts --filter 'published = true' --sort '-created' --per-page 50
pb records get posts RECORD_ID
pb records create posts '{"title":"first","published":true}'
pb records update posts RECORD_ID '{"published":false}'
pb records rm posts RECORD_ID
Testing your rules
The admin panel’s API preview on each collection shows the exact REST
endpoints and lets you copy example requests. A quick way to verify rules is
to call the API without a token and confirm you get a 403 or filtered
results, then repeat with a logged-in user.
From the terminal, pb records ls runs as the superuser (rules don’t apply to
it), so test the rules themselves with an unauthenticated request:
curl https://<instance-name>.pocketbasecloud.com/api/collections/posts/records
Important: never leave Create/Update/Delete rules empty on a production collection unless you truly want them public. Locked-by-default is the safe starting point.
Moving a schema between instances
Once a schema is right on one instance, copy it to another — staging to production, or a local instance to the cloud.
Using the portal
The project’s Collections page has Export and Import dialogs, and the admin panel has its own under Settings → Import collections.
Using the CLI
pb use https://staging.pocketbasecloud.com && pb login
pb collections export --out collections.json
pb use https://production.pocketbasecloud.com && pb login
pb collections import collections.json
--delete-missing makes the import an exact mirror by dropping collections not
present in the file — it asks for confirmation first, and it drops their data
with them.