Skip to content

Instantly share code, notes, and snippets.

@Jensderond
Created June 11, 2026 11:26
Show Gist options
  • Select an option

  • Save Jensderond/c802f24e7852f1b0883cb3dcff7bf501 to your computer and use it in GitHub Desktop.

Select an option

Save Jensderond/c802f24e7852f1b0883cb3dcff7bf501 to your computer and use it in GitHub Desktop.
meili-status.sh — Check Meilisearch indexes and document counts
#!/usr/bin/env bash
#
# meili-status.sh — Check Meilisearch indexes and document counts.
#
# Talks directly to the Meilisearch HTTP API using the master key, so it needs
# nothing from Craft/DDEV. Use it to verify a migration/reindex finished:
# it lists every index, how many documents each holds, and whether any index
# is still indexing.
#
# Usage (on the server, where Meilisearch listens on localhost:7700):
# MEILI_KEY=<master-key> ./meili-status.sh
#
# Or pass the key as a flag:
# ./meili-status.sh --key <master-key>
#
# Optional:
# --host http://... Override host (default: http://localhost:7700)
# --prefix dev Only show indexes starting with this prefix
# --watch Refresh every 5s until nothing is indexing, then exit
#
# Requirements: curl. (jq is used for pretty output if available, but not required.)
set -euo pipefail
HOST="${MEILI_HOST:-http://localhost:7700}"
KEY="${MEILI_KEY:-}"
PREFIX=""
WATCH=0
while [[ $# -gt 0 ]]; do
case "$1" in
--host) HOST="$2"; shift 2 ;;
--key) KEY="$2"; shift 2 ;;
--prefix) PREFIX="$2"; shift 2 ;;
--watch) WATCH=1; shift ;;
-h|--help)
grep '^#' "$0" | sed 's/^# \{0,1\}//'
exit 0 ;;
*) echo "Unknown argument: $1" >&2; exit 1 ;;
esac
done
if [[ -z "$KEY" ]]; then
echo "Error: set MEILI_KEY (env var or --key flag) to the Meilisearch master key." >&2
echo "Host defaults to ${HOST}; override with MEILI_HOST or --host." >&2
echo "Run with --help for usage." >&2
exit 1
fi
HOST="${HOST%/}" # strip trailing slash
have_jq=0
if command -v jq >/dev/null 2>&1; then have_jq=1; fi
fetch() {
# $1 = path; returns body, fails on non-2xx
curl -fsS -H "Authorization: Bearer ${KEY}" "${HOST}${1}"
}
print_status() {
echo "Meilisearch @ ${HOST}"
# Version / health sanity check.
if version_json=$(fetch "/version" 2>/dev/null); then
if [[ $have_jq -eq 1 ]]; then
echo "Version: $(echo "$version_json" | jq -r '.pkgVersion')"
fi
else
echo "Error: could not reach Meilisearch or master key rejected (check /version)." >&2
exit 2
fi
echo "----------------------------------------------------------------------"
stats_json=$(fetch "/stats")
if [[ $have_jq -eq 1 ]]; then
printf "%-45s %12s %s\n" "INDEX" "DOCUMENTS" "STATUS"
echo "$stats_json" | jq -r --arg p "$PREFIX" '
.indexes
| to_entries
| map(select($p == "" or (.key | startswith($p))))
| sort_by(.key)
| .[]
| [ .key,
(.value.numberOfDocuments | tostring),
(if .value.isIndexing then "INDEXING…" else "ready" end)
] | @tsv' \
| while IFS=$'\t' read -r name docs status; do
printf "%-45s %12s %s\n" "$name" "$docs" "$status"
done
total=$(echo "$stats_json" | jq -r '.databaseSize // 0')
indexing=$(echo "$stats_json" | jq -r '[.indexes[].isIndexing] | any')
echo "----------------------------------------------------------------------"
echo "Database size: $(( total / 1024 / 1024 )) MB"
if [[ "$indexing" == "true" ]]; then
echo "Overall: at least one index is still INDEXING."
else
echo "Overall: all indexes ready."
fi
else
# No jq: dump raw JSON, still useful for the sysadmin.
echo "(jq not installed — showing raw /stats JSON)"
echo "$stats_json"
fi
}
if [[ $WATCH -eq 1 && $have_jq -eq 1 ]]; then
while true; do
clear
print_status
indexing=$(fetch "/stats" | jq -r '[.indexes[].isIndexing] | any')
[[ "$indexing" == "false" ]] && { echo; echo "Done — nothing indexing."; break; }
sleep 5
done
else
print_status
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment