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

4.9 KiB

title aliases tags sources created updated
Search Plugin
plugin-search
payload-search
search-index
payloadcms
plugin
search
indexing
raw/plugins__search.md
2026-05-15 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

pnpm add @payloadcms/plugin-search

Basic Setup

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

searchPlugin({
  beforeSync: ({ originalDoc, searchDoc }) => ({
    ...searchDoc,
    excerpt: originalDoc?.excerpt || 'Fallback excerpt',
  }),
})

searchOverrides — Extend the Search Collection

searchPlugin({
  searchOverrides: {
    slug: 'search-results',
    fields: ({ defaultFields }) => [
      ...defaultFields,
      { name: 'excerpt', type: 'textarea' },
    ],
  },
})

skipSync — Conditional Indexing

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

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-insyncDrafts: false by default; set deleteDrafts: true to remove drafts from search
  • Reindex button covers existing data migration when adding plugin to existing projects

Sources