Audits
An audit runs the checks against the index and records what it found. Nothing changes until you ask it to.
Quick and deep
A quick audit is set comparisons in SQL. It finds orphaned rows, unindexed elements, partly indexed elements, stale field rows, rows for attributes an element type no longer claims, elements with no keywords at all, rows that hit the storage ceiling, and Craft’s own pending index backlog. It does not load a single element, and finishes in seconds on a large site.
A deep audit does all of that, and then reads each element, works out the keywords Craft would write for it right now, and compares them with what is stored. It is the only way to catch content that changed without the index being told:
- an import that wrote to the database directly
- a plugin update that changed how a field produces keywords
- a queue that was failing quietly
It costs one element load apiece. That is why it runs on the queue by default and stops at a configurable number of elements per type, newest first.
| Quick | Deep | |
|---|---|---|
| Loads elements | No | Yes |
| Finds keyword drift | No | Yes |
| Typical runtime | Seconds | Minutes |
| Runs on the queue | No | Yes, by default |
| Safe on production | Yes — read-only | Yes, within the deep limit |
Scoping a run
The new-audit form takes three narrowings, all optional:
- Sites — all of them, or particular ones. Worth using on a multi-site install where only one site is suspect.
- Element types — all, or particular classes. A site with a million Commerce order elements can leave them out of every routine audit.
- Checks — all enabled ones, or a named subset. Useful when you are chasing one specific problem and want the answer in seconds.
The settings hold the defaults for all three, plus a permanent list of checks and element types to skip.
Reading the report
Every finding carries a severity:
| Severity | Means |
|---|---|
| Critical | Content that cannot be found, or index rows that will never be cleaned up |
| Warning | Something is out of step and searches are affected |
| Notice | Worth knowing, working as designed |
Severity belongs to the finding, not to the check. The same check can report a critical and a notice in one run — empty keywords on a normal entry is a fault, and empty keywords on a Matrix block is how Craft works.
Counts, and why the list is capped
Every check runs a COUNT for its headline and a limited query for the detail. A site with 400,000 orphaned rows gets one line saying so and a sample beneath it, not 400,000 rows in the report. The cap is maxIssuesPerCheck, 500 by default, and the overflow is shown as an and N more line.
The count is what you act on. A fix works from its own fresh detection pass, not from the report, so a capped list never means a partial repair.
Fixing
Findings that Holmes can do something about carry a fix — usually Reindex or Delete rows. You can apply one, or apply all of a check’s findings at once. Fixes are covered in Repairs & sync.
History and retention
Finished audits are kept so you can compare runs — the useful question after a deploy is usually not what is wrong but what is newly wrong. Holmes keeps the last 20 by default and prunes older ones, with their findings, after each run. Set retentionCount to 0 to keep everything.
From the console
# a quick audit of everything
php craft holmes/audit
# deep, with no cap on elements per type
php craft holmes/audit --mode=deep --deep-limit=0
# just the two checks you care about
php craft holmes/audit --checks=orphaned-rows,unindexed-elements
# audit and repair in one go
php craft holmes/audit --fix
# what checks are registered, and which are deep
php craft holmes/audit/checks
# re-read a stored report
php craft holmes/audit/show 12
In CI
--fail-on=critical makes the command exit non-zero when it finds something at or above that severity, which is what you want after a deploy or a content migration:
php craft holmes/audit --mode=deep --fail-on=critical