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

# Base collections

> Standard collections for storing any type of data in your PocketBase application

Base collections are the standard collection type in PocketBase. They provide a flexible way to store any kind of structured data with custom fields and validation rules.

## When to use base collections

Use base collections when you need to:

* Store general application data (posts, products, comments, etc.)
* Create custom data structures without authentication features
* Build relationships between different data types
* Store file uploads alongside other data

<Info>
  If you need user authentication, use [auth collections](/collections/auth-collections) instead. For read-only data from SQL queries, use [view collections](/collections/view-collections).
</Info>

## Creating a base collection

Create a base collection using the factory function:

```go theme={null}
collection := core.NewBaseCollection("posts")
```

This initializes a collection with:

* Type set to `"base"`
* A default `id` field (15-character lowercase alphanumeric)
* Empty fields list ready for your custom fields

### With a custom ID

You can optionally specify a custom collection ID:

```go theme={null}
collection := core.NewBaseCollection("posts", "pbc_custom_id")
```

<Note>
  Collection IDs are automatically generated based on the type and name if not specified. The ID format is `pbc_` followed by a CRC32 checksum.
</Note>

## Default fields

Every base collection automatically includes an `id` field:

```go theme={null}
&TextField{
    Name:                "id",
    System:              true,
    PrimaryKey:          true,
    Required:            true,
    Min:                 15,
    Max:                 15,
    Pattern:             "^[a-z0-9]+$",
    AutogeneratePattern: "[a-z0-9]{15}",
}
```

This field:

* Is automatically generated for new records
* Cannot be changed after creation
* Serves as the primary key for the collection
* Is always required and system-managed

## Complete example

Here's a complete example of creating a blog posts collection:

```go theme={null}
package main

import (
    "log"
    "github.com/pocketbase/pocketbase"
    "github.com/pocketbase/pocketbase/core"
)

func main() {
    app := pocketbase.New()

    app.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
        // Create the posts collection
        posts := core.NewBaseCollection("posts")

        // Add custom fields
        posts.Fields.Add(
            &core.TextField{
                Name:     "title",
                Required: true,
                Min:      3,
                Max:      200,
            },
            &core.TextField{
                Name:     "slug",
                Required: true,
                Pattern:  "^[a-z0-9-]+$",
                Max:      200,
            },
            &core.EditorField{
                Name:     "content",
                Required: true,
            },
            &core.BoolField{
                Name: "published",
            },
            &core.RelationField{
                Name:         "author",
                Required:     true,
                CollectionId: "users_collection_id",
                MaxSelect:    1,
            },
            &core.RelationField{
                Name:         "categories",
                CollectionId: "categories_collection_id",
                MaxSelect:    5,
            },
            &core.FileField{
                Name:      "featured_image",
                MaxSelect: 1,
                MaxSize:   5242880, // 5MB
                MimeTypes: []string{"image/jpeg", "image/png", "image/webp"},
            },
        )

        // Add indexes for better performance
        posts.AddIndex("idx_slug", true, "`slug`", "")
        posts.AddIndex("idx_published", false, "`published`", "")

        // Set API rules
        posts.ListRule = core.String("")
        posts.ViewRule = core.String("")
        posts.CreateRule = core.String("@request.auth.id != ''")
        posts.UpdateRule = core.String("@request.auth.id = author")
        posts.DeleteRule = core.String("@request.auth.id = author")

        // Save the collection
        if err := e.App.Save(posts); err != nil {
            return err
        }

        return e.Next()
    })

    if err := app.Start(); err != nil {
        log.Fatal(err)
    }
}
```

## Field configuration

Base collections support all available field types. Here are some common patterns:

### Text fields with validation

```go theme={null}
&core.TextField{
    Name:     "username",
    Required: true,
    Min:      3,
    Max:      30,
    Pattern:  "^[a-zA-Z0-9_]+$",
}
```

### Numeric fields with constraints

```go theme={null}
&core.NumberField{
    Name:     "price",
    Required: true,
    Min:      core.Float64(0),
    Max:      core.Float64(999999.99),
}
```

### Relations to other collections

```go theme={null}
// Single relation
&core.RelationField{
    Name:         "category",
    Required:     true,
    CollectionId: categoryCollectionId,
    MaxSelect:    1,
}

// Multiple relations
&core.RelationField{
    Name:         "tags",
    CollectionId: tagCollectionId,
    MaxSelect:    10,
}
```

### File uploads

```go theme={null}
&core.FileField{
    Name:      "attachments",
    MaxSelect: 5,
    MaxSize:   10485760, // 10MB
    MimeTypes: []string{
        "application/pdf",
        "application/msword",
        "text/plain",
    },
}
```

## Setting API rules

Control access to your collection with API rules:

<Steps>
  <Step title="Allow public read access">
    ```go theme={null}
    collection.ListRule = core.String("")
    collection.ViewRule = core.String("")
    ```
  </Step>

  <Step title="Require authentication for writes">
    ```go theme={null}
    collection.CreateRule = core.String("@request.auth.id != ''")
    ```
  </Step>

  <Step title="Owner-only updates and deletes">
    ```go theme={null}
    collection.UpdateRule = core.String("@request.auth.id = owner")
    collection.DeleteRule = core.String("@request.auth.id = owner")
    ```
  </Step>
</Steps>

### Common rule patterns

```go theme={null}
// Public read, authenticated write
collection.ListRule = core.String("")
collection.ViewRule = core.String("")
collection.CreateRule = core.String("@request.auth.id != ''")
collection.UpdateRule = nil // Deny all
collection.DeleteRule = nil // Deny all

// Owner-based access
collection.ListRule = core.String("")
collection.ViewRule = core.String("")
collection.CreateRule = core.String("@request.auth.id != ''")
collection.UpdateRule = core.String("@request.auth.id = userId")
collection.DeleteRule = core.String("@request.auth.id = userId")

// Role-based access
collection.CreateRule = core.String("@request.auth.role = 'admin'")
collection.UpdateRule = core.String("@request.auth.role = 'admin' || @request.auth.role = 'editor'")
```

<Warning>
  Setting a rule to `nil` denies all access. Setting it to `""` allows all access. Use filter expressions for conditional access.
</Warning>

## Adding indexes

Indexes improve query performance for frequently searched fields:

```go theme={null}
// Unique index on email
collection.AddIndex("idx_unique_email", true, "`email`", "")

// Composite index on multiple fields
collection.AddIndex("idx_user_status", false, "`userId`, `status`", "")

// Conditional index
collection.AddIndex(
    "idx_active_users",
    false,
    "`createdAt`",
    "`status` = 'active'",
)
```

### Index parameters

* **Name**: Unique identifier for the index
* **Unique**: Whether the index enforces uniqueness
* **Columns**: SQL expression for indexed columns (use backticks)
* **Where**: Optional WHERE clause for conditional indexes

## Updating collections

You can modify existing collections by finding them first:

```go theme={null}
collection, err := app.FindCollectionByNameOrId("posts")
if err != nil {
    return err
}

// Add a new field
collection.Fields.Add(
    &core.DateField{
        Name: "publishedAt",
    },
)

// Save the changes
if err := app.Save(collection); err != nil {
    return err
}
```

<Note>
  PocketBase handles schema migrations automatically when you save collection changes. Existing data is preserved when adding new fields.
</Note>

## Best practices

<Tabs>
  <Tab title="Naming">
    * Use plural names for collections (`posts`, `users`, `categories`)
    * Use snake\_case or camelCase for field names
    * Keep names descriptive but concise
  </Tab>

  <Tab title="Validation">
    * Set appropriate min/max constraints on fields
    * Use `Required` only when truly necessary
    * Add indexes to fields used in queries
  </Tab>

  <Tab title="Security">
    * Start with restrictive rules and loosen as needed
    * Test API rules thoroughly before deploying
    * Use `@request.auth` to implement ownership checks
  </Tab>

  <Tab title="Performance">
    * Add indexes to frequently queried fields
    * Limit relation depth in queries
    * Use view collections for complex read-only queries
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Auth collections" icon="user-lock" href="/collections/auth-collections">
    Add user authentication to your app
  </Card>

  <Card title="Fields reference" icon="list" href="/collections/fields">
    Explore all available field types
  </Card>

  <Card title="View collections" icon="eye" href="/collections/view-collections">
    Create read-only SQL-based collections
  </Card>

  <Card title="API rules" icon="shield" href="/concepts/api-rules">
    Learn about the rule syntax
  </Card>
</CardGroup>
