obsidian/wiki/payloadcms/plugin-search.md
2026-05-15 16:24:24 +01:00

139 lines
4.9 KiB
Markdown

---
title: "Search Plugin"
aliases: [plugin-search, payload-search, search-index]
tags: [payloadcms, plugin, search, indexing]
sources: [raw/plugins__search.md]
created: 2026-05-15
updated: 2026-05-15
---
## Overview
`@payloadcms/plugin-search` creates a dedicated `search` collection that mirrors only search-critical fields from your enabled collections. Records are automatically synced on document create/update/delete via hooks, and can be queried with standard Payload APIs — no third-party service required.
## How It Works
1. Plugin adds a `search` collection to your database with an index
2. Enabled collections get `beforeChange` + `afterDelete` hooks
3. On save → a lightweight search record (title, excerpt, slug, etc.) is created/updated
4. On delete → search record is removed
5. Queries hit the `search` collection directly — bypassing all hooks on the original collection
## Installation
```bash
pnpm add @payloadcms/plugin-search
```
## Basic Setup
```ts
import { searchPlugin } from '@payloadcms/plugin-search'
export default buildConfig({
plugins: [
searchPlugin({
collections: ['pages', 'posts'],
defaultPriorities: {
pages: 10,
posts: 20,
},
}),
],
})
```
## Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `collections` | `string[]` | required | Slugs of collections to index |
| `localize` | `boolean` | `true` | Add localization to `title` field if i18n is enabled |
| `defaultPriorities` | `Record<slug, number \| fn>` | — | Fallback `priority` on create; fn receives `doc` |
| `searchOverrides` | `Partial<CollectionConfig>` | — | Merge into the auto-created `search` collection config |
| `beforeSync` | `afterChange hook` | — | Modify/fallback search doc data before create/update |
| `syncDrafts` | `boolean` | `false` | Sync draft documents to search index |
| `deleteDrafts` | `boolean` | `true` | Delete search record when doc status changes to draft |
| `skipSync` | `async fn` | — | Return `true` to skip a specific doc/locale combination |
| `reindexBatchSize` | `number` | `50` | Batch size for on-demand reindexing |
### `beforeSync` — Modify Data Before Index
```ts
searchPlugin({
beforeSync: ({ originalDoc, searchDoc }) => ({
...searchDoc,
excerpt: originalDoc?.excerpt || 'Fallback excerpt',
}),
})
```
### `searchOverrides` — Extend the Search Collection
```ts
searchPlugin({
searchOverrides: {
slug: 'search-results',
fields: ({ defaultFields }) => [
...defaultFields,
{ name: 'excerpt', type: 'textarea' },
],
},
})
```
### `skipSync` — Conditional Indexing
```ts
searchPlugin({
skipSync: async ({ locale, doc, collectionSlug, req }) => {
if (!locale) return false
const tenant = await req.payload.findByID({ collection: 'tenants', id: doc.tenant.id })
return !tenant.allowedLocales.includes(locale)
},
})
```
`skipSync` is called **once per locale per document**. Return `true` = skip, `false` = proceed.
## Priority & Sorting
- Every search record gets a `priority` field
- Use `?sort=priority` (ascending) to order results by collection type
- `defaultPriorities` sets the initial value at create time
- Can be a static number or a function: `({ doc }) => doc.featured ? 1 : 10`
## On-Demand Reindexing
- Navigate to the `search` collection in the Admin Panel
- Click the **Reindex** pill (top-right action slot)
- Select a specific collection or "all" to rebuild indexes
- Useful when adding the plugin to an existing project with existing documents
## TypeScript
```ts
import type { SearchConfig, BeforeSync } from '@payloadcms/plugin-search/types'
```
## Key Takeaways
- **First-party Algolia alternative** — no external service; runs on your own DB
- **Static snapshots bypass hooks** — queries on `search` collection don't trigger hooks on original docs, making them significantly faster
- **You control what's indexed** — only sync fields you need (title, slug, excerpt)
- **Priority field enables ranked results** — pass `?sort=priority` to order by collection or document importance
- **`skipSync` is per locale** — called once per locale per document; useful for multi-tenant locale filtering
- **Draft handling is opt-in** — `syncDrafts: false` by default; set `deleteDrafts: true` to remove drafts from search
- **Reindex button** covers existing data migration when adding plugin to existing projects
## Related
- [[wiki/payloadcms/plugins|Plugins Overview + Official]] — all 10 official plugins
- [[wiki/payloadcms/plugins-api|Plugin API]] — build custom plugins
- [[wiki/payloadcms/hooks-collections|Collection Hooks]] — `beforeChange`/`afterDelete` hooks used internally
- [[wiki/payloadcms/queries|Queries]] — querying the `search` collection with `?sort=priority`
- [[wiki/payloadcms/localization|Localization]] — `localize` option and `skipSync` locale parameter
## Sources
- `raw/plugins__search.md` — https://payloadcms.com/docs/plugins/search