Collection types
PocketBase supports three types of collections:- Base - Standard collections for general data storage
- Auth - Collections with built-in authentication (email, password, OAuth2)
- View - Read-only collections based on SQL queries
Creating collections
Base collection
const collection = new Collection({
name: "posts",
type: "base",
listRule: "@request.auth.id != ''",
viewRule: "@request.auth.id != ''",
createRule: "@request.auth.id != ''",
updateRule: "@request.auth.id = author",
deleteRule: "@request.auth.id = author",
fields: [
{
name: "title",
type: "text",
required: true,
min: 3,
max: 200,
},
{
name: "content",
type: "editor",
required: true,
},
{
name: "author",
type: "relation",
required: true,
collectionId: $app.findCollectionByNameOrId("users").id,
maxSelect: 1,
},
],
})
$app.save(collection)
Auth collection
const collection = new Collection({
name: "customers",
type: "auth",
authRule: "@request.auth.id != '' && verified = true",
manageRule: "@request.auth.id != '' && @request.auth.role = 'admin'",
fields: [
{
name: "company",
type: "text",
required: true,
},
{
name: "role",
type: "select",
required: true,
values: ["user", "admin", "moderator"],
},
{
name: "avatar",
type: "file",
maxSelect: 1,
maxSize: 5242880, // 5MB
mimeTypes: ["image/jpeg", "image/png"],
},
],
})
$app.save(collection)
View collection
const collection = new Collection({
name: "posts_with_authors",
type: "view",
viewQuery: `
SELECT
posts.id,
posts.title,
posts.created,
users.username as author_name,
users.email as author_email
FROM posts
LEFT JOIN users ON posts.author = users.id
`,
listRule: "@request.auth.id != ''",
viewRule: "@request.auth.id != ''",
})
$app.save(collection)
Field types
PocketBase supports multiple field types. Here are examples of each:Text field
new TextField({
name: "title",
required: true,
min: 3,
max: 200,
pattern: "^[a-zA-Z0-9\\s]+$", // Alphanumeric with spaces
})
Number field
new NumberField({
name: "price",
required: true,
min: 0,
max: 999999,
onlyInt: false, // Allow decimals
})
Boolean field
new BoolField({
name: "featured",
required: false,
})
Email field
new EmailField({
name: "contact_email",
required: true,
exceptDomains: ["tempmail.com", "throwaway.email"],
})
URL field
new URLField({
name: "website",
required: false,
onlyDomains: ["example.com", "trusted-site.com"],
})
Date field
new DateField({
name: "publish_date",
required: true,
min: "2024-01-01 00:00:00.000Z",
max: "2025-12-31 23:59:59.999Z",
})
Select field
new SelectField({
name: "status",
required: true,
values: ["draft", "published", "archived"],
maxSelect: 1, // Single select
})
// Multi-select
new SelectField({
name: "tags",
required: false,
values: ["javascript", "typescript", "go", "python"],
maxSelect: 5, // Allow multiple selections
})
JSON field
new JSONField({
name: "metadata",
required: false,
maxSize: 2000000, // 2MB max
})
File field
new FileField({
name: "attachments",
required: false,
maxSelect: 5, // Up to 5 files
maxSize: 10485760, // 10MB per file
mimeTypes: [
"image/jpeg",
"image/png",
"application/pdf",
"application/zip",
],
thumbs: ["100x100", "500x500"], // Image thumbnails
protected: false, // Public access
})
Relation field
new RelationField({
name: "author",
required: true,
collectionId: $app.findCollectionByNameOrId("users").id,
maxSelect: 1, // Single relation
cascadeDelete: false, // Don't delete related records
})
// Many-to-many relation
new RelationField({
name: "categories",
required: false,
collectionId: $app.findCollectionByNameOrId("categories").id,
maxSelect: 10, // Multiple relations
cascadeDelete: false,
})
Editor field
new EditorField({
name: "content",
required: true,
maxSize: 5000000, // 5MB
convertUrls: true, // Convert file URLs to relative paths
})
Autodate field
new AutodateField({
name: "updated_at",
onCreate: false, // Don't set on create
onUpdate: true, // Update on every save
})
new AutodateField({
name: "created_at",
onCreate: true, // Set once on create
onUpdate: false, // Don't change on updates
})
Access rules
Access rules use a filter syntax to control who can perform operations on collections.Common patterns
// Public read, authenticated write
const collection = new Collection({
name: "articles",
type: "base",
listRule: "", // Anyone can list
viewRule: "", // Anyone can view
createRule: "@request.auth.id != ''", // Must be authenticated
updateRule: "@request.auth.id = author", // Must be the author
deleteRule: "@request.auth.id = author",
})
Role-based access
const collection = new Collection({
name: "admin_posts",
type: "base",
listRule: "@request.auth.role = 'admin'",
viewRule: "@request.auth.role = 'admin'",
createRule: "@request.auth.role = 'admin'",
updateRule: "@request.auth.role = 'admin'",
deleteRule: "@request.auth.role = 'admin'",
})
Field-level access
const collection = new Collection({
name: "posts",
type: "base",
// Only show published posts to non-authors
listRule: "status = 'published' || @request.auth.id = author",
viewRule: "status = 'published' || @request.auth.id = author",
// Can create if authenticated
createRule: "@request.auth.id != ''",
// Can only update own posts and only certain fields
updateRule: "@request.auth.id = author && @request.data.status:isset = false",
})
Finding collections
// By name
const collection = $app.findCollectionByNameOrId("posts")
// By ID
const collection = $app.findCollectionByNameOrId("abc123def456")
// Get all collections
const collections = arrayOf(new Collection())
$app.findAllCollections(collections)
for (let col of collections) {
console.log(col.name, col.type)
}
Updating collections
Modify existing fields
const collection = $app.findCollectionByNameOrId("posts")
// Update a field
const fields = collection.fields
for (let i = 0; i < fields.length; i++) {
if (fields[i].name === "title") {
fields[i].max = 300 // Increase max length
}
}
collection.fields = fields
$app.save(collection)
Add new fields
const collection = $app.findCollectionByNameOrId("posts")
const fields = collection.fields
fields.push(new TextField({
name: "excerpt",
required: false,
max: 500,
}))
fields.push(new NumberField({
name: "view_count",
required: false,
min: 0,
onlyInt: true,
}))
collection.fields = fields
$app.save(collection)
Update rules
const collection = $app.findCollectionByNameOrId("posts")
// Make collection public for reading
collection.listRule = ""
collection.viewRule = ""
// But still require auth for modifications
collection.createRule = "@request.auth.id != ''"
collection.updateRule = "@request.auth.id = author"
collection.deleteRule = "@request.auth.id = author"
$app.save(collection)
Deleting collections
Deleting a collection will permanently delete all records in that collection. This action cannot be undone.
const collection = $app.findCollectionByNameOrId("old_posts")
$app.delete(collection)
Migration example
Here’s a complete example of creating a blog schema:// pb_migrations/1234567890_create_blog.js
migrate(
// Up migration
(app) => {
// Categories collection
const categories = new Collection({
name: "categories",
type: "base",
listRule: "",
viewRule: "",
createRule: "@request.auth.role = 'admin'",
updateRule: "@request.auth.role = 'admin'",
deleteRule: "@request.auth.role = 'admin'",
fields: [
{
name: "name",
type: "text",
required: true,
min: 2,
max: 100,
},
{
name: "slug",
type: "text",
required: true,
pattern: "^[a-z0-9-]+$",
},
],
})
app.save(categories)
// Posts collection
const posts = new Collection({
name: "posts",
type: "base",
listRule: "status = 'published' || @request.auth.id = author",
viewRule: "status = 'published' || @request.auth.id = author",
createRule: "@request.auth.id != ''",
updateRule: "@request.auth.id = author",
deleteRule: "@request.auth.id = author",
fields: [
{
name: "title",
type: "text",
required: true,
min: 3,
max: 200,
},
{
name: "slug",
type: "text",
required: true,
pattern: "^[a-z0-9-]+$",
},
{
name: "content",
type: "editor",
required: true,
},
{
name: "excerpt",
type: "text",
max: 500,
},
{
name: "featured_image",
type: "file",
maxSelect: 1,
maxSize: 5242880,
mimeTypes: ["image/jpeg", "image/png", "image/webp"],
thumbs: ["200x200", "800x600"],
},
{
name: "author",
type: "relation",
required: true,
collectionId: app.findCollectionByNameOrId("users").id,
maxSelect: 1,
},
{
name: "categories",
type: "relation",
collectionId: categories.id,
maxSelect: 5,
},
{
name: "status",
type: "select",
required: true,
values: ["draft", "published", "archived"],
},
{
name: "published_at",
type: "date",
},
],
})
app.save(posts)
return null
},
// Down migration
(app) => {
app.delete(app.findCollectionByNameOrId("posts"))
app.delete(app.findCollectionByNameOrId("categories"))
return null
}
)