videre prune
Syncs the database with what is actually on disk. It never deletes real files: only database rows, and cached data derived from photos that are already gone.
videre prune --dry-run # show what would be removedvidere prune # remove stale entries and refresh metadatavidere prune --silent # no per-file outputvidere --library ~/Photos prune # select a different libraryvidere prune --prune-unreachable # also drop entries whose folder is gonevidere prune --force # allow an unusually large cleanupWhen to run it
Section titled “When to run it”The usual moment is right after deleting duplicates:
videre dedupe --remove # files are gone from disk (moved to the trash)...videre prune # ...now the database agreesUntil you do, videre stats still counts the deleted files, and reports still
list them (they are filtered out at generation time, but the rows remain).
Also worth running after moving or reorganising folders by hand, since rows are keyed by path: a moved file looks like a deletion plus a new file, and the old row lingers until pruned.
Always look first on a library you care about:
videre prune --dry-runWhat one pass does
Section titled “What one pass does”- Removes rows for files no longer on disk
- Refreshes the stored timestamp of any file whose modification time has changed since the last pass
- Removes face detections and face-scan markers whose content has no indexed path. Person names and the learning journal remain; evidence from removed faces becomes ineligible, pending questions are withdrawn, and an active learned profile is retired if an eligible event lost its source
- Deletes embeddings whose photo is gone, across every model
- Deletes cached thumbnails whose photo is gone
- Removes any model database the sweep has left with no
embeddings at all, typically one an interrupted or failed
videre embedleft behind
Steps 4 and 5 reclaim derived data on disk. Step 3 keeps the People page and face learning consistent with the indexed files.
Step 2 only touches rows that actually differ, so the count tells you something.
Its usual cause is another program changing a file’s modification time.
videre fix-dates is not one: it records the times it
writes. On a library nothing has touched, the count is zero and a second pass
is a no-op.
If two paths share the same content and only one is deleted, the shared embedding and cache entries are kept. They are keyed by content, so they are still in use by the surviving copy. The same rule protects faces and face-scan markers.
If a drive is not plugged in, prune leaves it alone
Section titled “If a drive is not plugged in, prune leaves it alone”A row is only removed when the file is missing and its parent folder still exists. A missing folder means the drive or directory is gone, not that you deleted the photos:
12,431 row(s) skipped as unreachable (1 directory missing: /Volumes/Photos) run with --prune-unreachable to remove them anywayThis is a data-safety guard, not tidiness. prune used to treat every unreadable file as deleted, so running it with a drive unplugged removed every row for that drive. The rows are the cheap part: once they are gone, their embeddings and cached thumbnails look orphaned and the sweeps take those too. That is hours of recompute against minutes to re-scan.
Consequences worth knowing:
- Skipped rows keep everything downstream safe. Protecting the row protects its embeddings and thumbnails automatically.
- The skip count prints even under
--silent, and names up to 5 missing directories. A run that quietly skips thousands of rows is exactly the silence this fixes. - A deliberately deleted subfolder is skipped too, and its rows linger until
you pass
--prune-unreachable. The conservative direction is the safe one.
Use --prune-unreachable when a folder really is gone for good, having checked
that the drive is not merely unmounted.
Two further guards
Section titled “Two further guards”Bulk deletion. A run removing more than 20% of the library and at least 100
rows stops before deleting anything, and needs --force. Both conditions are
required: a percentage alone would block a five-row library where three files
were legitimately deleted, and a count alone would never trip on a small one.
This catches what the folder check misses, such as a volume that remounts empty.
Repeated failure. After 10 consecutive errors the run stops, printing the first error rather than one near-identical line per row. Consecutive, not cumulative, so a few scattered unreadable files do not abort a good run.
Earlier changes stay committed, and prune is idempotent, so rerunning after fixing the cause continues safely. That is also why hitting a guard is not a problem: nothing is half-done in a way a second run cannot finish.
Caveats
Section titled “Caveats”It acts on the whole database, not a folder. If you scanned several roots into one database, prune considers all of them, and there is no way to limit it to one. See scanning more than one folder.
It is the only thing that reclaims cache space, and only for photos already removed from the database. Cache for photos you still own grows without bound and is never touched here.
videre watch --prune can override neither guard. It runs unattended and
cannot ask, so bulk deletion and repeated failure remain active. That makes it
safe to leave on, but it also means an unattended prune can quietly decline to
do the thing you wanted; check videre stats if you expected space back.
Exits nonzero if any row update or cache removal failed, which is worth checking in a script.
More detail
Section titled “More detail”- Caches and disk use covers everything this can and cannot reclaim.
- Backing up covers what is worth keeping before a large cleanup.