Meilisearch
Add the official companion layer for atomic build-time indexing and optional browser search.
The official @kirchdev/duxt-meilisearch companion layer consumes the entire
duxt:search:records snapshot. It keeps URL-derived IDs,
normalized plaintext, source, version and locale, including generated sections.
Meilisearch is optional; the built-in search needs no service.
pnpm add @kirchdev/duxt-meilisearchexport default defineNuxtConfig({
extends: ['@kirchdev/duxt', '@kirchdev/duxt-meilisearch'],
duxtMeilisearch: {
host: process.env.MEILISEARCH_HOST,
index: 'docs',
searchKey: process.env.MEILISEARCH_SEARCH_KEY,
syncKey: process.env.MEILISEARCH_SYNC_KEY,
taskKey: process.env.MEILISEARCH_TASK_KEY,
sync: {
enabled: process.env.MEILISEARCH_SYNC_ENABLED === 'true',
deployment: process.env.DUXT_DEPLOYMENT === 'production'
? 'production' : 'preview'
}
}
})
Set both production opt-ins only in your production publication job. Possessing
syncKey alone enables no writes. Development, Nuxt prepare and recognized PR
or preview contexts skip synchronization; other CI systems must map preview
contexts to deployment: 'preview'. Cloudflare Pages also needs
DUXT_PRODUCTION_BRANCH to match CF_PAGES_BRANCH.
Use a dedicated docs index. Give the private build key indexes.create,
indexes.get, indexes.delete, indexes.swap, settings.update,
documents.add, and tasks.get for docs and docs__duxt_*.
The layer builds a unique staging index, waits for settings and document-import
tasks, swaps it atomically with docs, waits for successful publication, then
removes the prior snapshot. Later builds remove deleted pages, and empty builds
clear the index. Failed imports leave the previous live snapshot in place.
Uncertain swaps retain staging rather than deleting possibly published data;
cleanup failures are reported. Serialize publication jobs when build order
matters. The first sync creates an empty target after staging is complete.
The private key never enters browser runtime config. Browser integration is
separate: omit searchKey to retain built-in search while synchronizing. To
connect the existing dialog, create a separate key with only the search
action and only the configured docs index. The default search key covers
all indexes; do not use it. Never use a master or admin key in public config.
The provider rejects reuse of a known build key; opaque key strings do not reveal
permissions, so scoped provisioning is your responsibility. Browser-only use
needs no private build key. Allow your site's origin in the service's CORS policy.
Search keeps each artefact's selected/default version and the content-language
fallback chain. A translated page suppresses its original; a page lacking that
translation remains reachable in the original language. The companion reads a
cached page-path inventory through Content and excludes covered pages within
each source/version/locale scope before Meilisearch ranks and limits results.
The provider's filter-only page field holds the URL without its anchor;
hidden sections cannot consume the engine's 1,000-hit window. Synchronize once
before using browser search with an index created by an earlier provider build.
Service errors yield an empty result
and a console warning. HTTP requests time out after 30 seconds; build tasks have
a five-minute budget, configurable through sync.taskTimeoutMs (at most one hour).
This package has its own release version and changelog. It is a separate Nuxt
layer, with no SDK, credentials or provider configuration added to duxt.
The browser helper is exported at @kirchdev/duxt-meilisearch/search; explicit
build tooling may use @kirchdev/duxt-meilisearch/sync with the same opt-in.
The service guarantees come from Meilisearch's atomic index swap and asynchronous task API. See creating a scoped API key for the separate browser credential.
Meilisearch 1.54.3 hides the global indexSwap task (indexUid: null) from
index-restricted keys, even when they cover both swapped indexes. With a scoped
write key, supply a separate private taskKey with only actions: ['tasks.get']
and indexes: ['*']. It is used only for task polling and never enters public
config. Without it, syncKey must itself be able to read global tasks. A hidden
404 fails publication confirmation and retains staging; it is never taken as
success. This behavior was verified against the real engine.