Overview
Meilisearch is an open-source (MIT) search engine for instant, typo-tolerant, faceted search — a self-hosted alternative to Algolia, driven entirely by a REST API on a single port. This template deploys one Meilisearch server with persistent index storage, mandatory master-key authentication, an indexing memory budget derived from the container’s own memory limit, optional scheduled Meilisearch snapshots, and scheduled platform volume backups. The image is the Community build, compiled without any Enterprise code. Replication and sharding are not part of it, so the template runs exactly one replica (see Scaling and Availability).cpln workload exec, cpln logs and uninstalling all work against that GVC. Install into a GVC with a single location: a workload runs in every location its GVC has, and each location would get its own independent, diverging index behind one endpoint.What Gets Created
Prerequisites
Create the master-key secret
GET /health without a master key, and the key must be at least 16 bytes while server.env is production. Create an opaque secret whose entire payload is the key:auth.secretName to this name.Installation
Install with the secret name from the prerequisite step; every other value has a working default.UI
CLI
Terraform
Pulumi
Configuration
Image
Resources
MEILI_MAX_INDEXING_MEMORY is set to tuning.indexingMemoryPercent of resources.maxMemory (at the defaults, 1024MiB), and there is no absolute override, so it can never exceed the container’s own limit. Raise maxMemory to index faster and hold a larger index; raise indexingMemoryPercent (accepted range 20–80, enforced at render time) only if the instance indexes far more often than it searches.
maxCpu-to-minCpu ratio greater than 4:1 on a stateful workload. The defaults sit exactly at 4:1, so raising maxCpu means raising minCpu too.Storage
ext4 volume at /meili_data holds data.ms (the index), snapshots/ and dumps/. The chart rejects a capacity below 10 at render time.
Master Key
reveal on exactly that secret and nothing else.
Server
server.env: production, GET / returns HTTP 200 with {"status":"Meilisearch is running"} and no HTML. That is a healthy instance — the browser search-preview UI is only served with server.env: development. The master key protects every route either way.Metrics
metrics.get action.
Snapshots
.snapshot files, written onto the same volume. These are distinct from the platform volume snapshots under backup — see Backing Up for how the two relate.
Backup
/meili_data volume. No cloud account or bucket is needed. backup.enabled: false disables the schedule only; the final snapshot on delete is always taken and kept for backup.retention. Changing any backup value updates the volume set without restarting the workload.
Access
publicAccess or internalAccess, requests may keep returning the old behavior (or 503) for a while — re-test before concluding the knob does not work.Connecting
{"status":"available"}.
Use a Scoped API Key
On first boot Meilisearch derives four API keys from the master key. Fetch them once and hand the right one to each caller; never give the master key to a browser.Index and Search
Indexing is asynchronous: writes return202 Accepted with a taskUid you can poll on /tasks. From another workload in the GVC, replace localhost:7700 with the internal address above.
Interstellar document.
Operations
Backing Up
Two different things are called “snapshots” here, and they do different jobs:/tasks:
Restoring a Backup
What the chart does make true: the index, Meilisearch snapshots and dumps all live on theRELEASE_NAME-meilisearch-data volume set, which the platform snapshots on backup.schedule and on delete. Recovering from one of those snapshots therefore means restoring the volume set rather than anything inside Meilisearch — consult the volume set reference for the platform’s restore procedure. Test any procedure on a disposable release before relying on it.
Upgrading Meilisearch
Meilisearch refuses to open a database written by an older version, so raisingimage on a populated volume fails by design until you ask for the migration. The chart’s server.upgradeDb sets MEILI_UPGRADE_DB, the upstream in-place upgrade flag.
Confirm a recent backup exists
Deploy the new image with the migration flag
image to the new tag and server.upgradeDb: true in the same helm upgrade. The database is upgraded on startup.Turn the flag back off
server.upgradeDb: false and upgrade again so the migration flag is not left permanently on.Your database version (X) is incompatible with your current engine version (Y). and restarts in a loop. The previous, working version keeps serving for a while before the deployment goes not-ready, so a forgotten flag looks fine at first — check cpln workload get-deployments RELEASE_NAME-meilisearch --gvc GVC_NAME -o yaml, not just the first minute.
Scaling and Availability
The template runs exactly one replica, and there is noreplicas knob. Replication and sharding are Meilisearch Enterprise features that are not compiled into the Community image, so a second replica would serve a separate, empty index behind the same endpoint.
Consequences to plan around:
- A
helm upgradeor restart is a real outage of the search endpoint, and it begins some time after the command returns. Have your application fall back to a database query while search is unavailable. - An abrupt replica loss recovers on its own with data intact; the volume reattaches to the rescheduled replica.
- Scale vertically: raise
resources.maxMemory(which also raises the indexing budget) andvolumeset.capacity.
Troubleshooting
Deployment never becomes ready and cpln logs returns nothing
Deployment never becomes ready and cpln logs returns nothing
auth.secretName does not exist, or did not exist when the workload was created. The container never starts, so there is no container output to collect.Fix: read status.versions[].message, which names the missing secret:cpln workload force-redeployment RELEASE_NAME-meilisearch --gvc GVC_NAME.Container exits with: The master key must be at least 16 bytes in a production environment
Container exits with: The master key must be at least 16 bytes in a production environment
server.env is production.Fix: replace the secret’s value with a longer key (openssl rand -hex 32 produces 64 characters) and force a redeployment. Every derived API key changes with it.Container restarts with: Your database version (X) is incompatible with your current engine version (Y)
Container restarts with: Your database version (X) is incompatible with your current engine version (Y)
server.upgradeDb: true.Fix: follow Upgrading Meilisearch — redeploy with the same new tag and server.upgradeDb: true, then set it back to false.Import rejected with HTTP 413 payload_too_large
Import rejected with HTTP 413 payload_too_large
server.maxPayloadSize (default 100 MB). Nothing from that request is written.Fix: send the documents in smaller batches, or raise server.maxPayloadSize and upgrade the release.GET /metrics returns HTTP 400 feature_not_enabled
GET /metrics returns HTTP 400 feature_not_enabled
metrics.enabled is false (the default). The route exists but the experimental feature is off, so the answer is 400, not 404.Fix: set metrics.enabled: true, upgrade the release, and call the route with an API key that has the metrics.get action. Without any key the route answers 401.GET / returns JSON instead of the search-preview UI
GET / returns JSON instead of the search-preview UI
server.env is production, which suppresses the browser UI by design. {"status":"Meilisearch is running"} is a healthy answer.Fix: set server.env: development if you want the playground at /. The master key still protects every route.Writes fail with HTTP 403 invalid_api_key
Writes fail with HTTP 403 invalid_api_key
Important Notes
- Create the master-key secret before installing, and confirm it exists with
cpln secret reveal SECRET_NAME -o yaml; without it the deployment wedges silently. - Rotating the master key changes every derived API key and requires a forced redeployment to take effect — treat it as write-once.
- Never hand the master key to a browser; use the Default Search API Key for front-ends.
- Set
server.upgradeDb: truefor exactly one deploy when raising the image tag, then set it back tofalse. Confirm a backup first; the migration is not atomic. - Size indexing with
resources.maxMemory— the indexing budget is a percentage of it and has no absolute override. - Batch large imports below
server.maxPayloadSize; an oversized body is rejected with HTTP 413 and nothing is written. - Install into a single-location GVC; each location gets its own volume and its own diverging index.
- Uninstall deletes the volume set. A final snapshot is kept for
backup.retention; your master-key secret is left untouched.