> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/pocketbase/pocketbase/llms.txt
> Use this file to discover all available pages before exploring further.

# Collections

> Create and manage collections in JavaScript

Collections are the foundation of your PocketBase database. They define the structure of your data with fields, validation rules, and access controls.

## 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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
new TextField({
  name: "title",
  required: true,
  min: 3,
  max: 200,
  pattern: "^[a-zA-Z0-9\\s]+$", // Alphanumeric with spaces
})
```

### Number field

```javascript theme={null}
new NumberField({
  name: "price",
  required: true,
  min: 0,
  max: 999999,
  onlyInt: false, // Allow decimals
})
```

### Boolean field

```javascript theme={null}
new BoolField({
  name: "featured",
  required: false,
})
```

### Email field

```javascript theme={null}
new EmailField({
  name: "contact_email",
  required: true,
  exceptDomains: ["tempmail.com", "throwaway.email"],
})
```

### URL field

```javascript theme={null}
new URLField({
  name: "website",
  required: false,
  onlyDomains: ["example.com", "trusted-site.com"],
})
```

### Date field

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
new JSONField({
  name: "metadata",
  required: false,
  maxSize: 2000000, // 2MB max
})
```

### File field

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
new EditorField({
  name: "content",
  required: true,
  maxSize: 5000000, // 5MB
  convertUrls: true, // Convert file URLs to relative paths
})
```

### Autodate field

```javascript theme={null}
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

```javascript theme={null}
// 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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
// 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

```javascript theme={null}
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

```javascript theme={null}
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

```javascript theme={null}
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

<Warning>
  Deleting a collection will permanently delete all records in that collection. This action cannot be undone.
</Warning>

```javascript theme={null}
const collection = $app.findCollectionByNameOrId("old_posts")
$app.delete(collection)
```

## Migration example

Here's a complete example of creating a blog schema:

```javascript theme={null}
// 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
  }
)
```
