A comparison page that ranks puts the verdict in the first paragraph, a spec table in the first screenful, and lives at exactly one URL per pair. Someone searching "immich vs photoprism" has finished discovering options; they want a decision with evidence. Pages that hedge for 800 words before committing lose to pages that commit in 50 — and on this site, moving the verdict from the conclusion to the opening was worth roughly a 20% CTR improvement on the comparison template, because the snippet started answering the query.
Verdict first, justification after
The verdict is one sentence plus the condition that flips it: "Immich, unless your library is a decade of pre-smartphone folders — then PhotoPrism's filesystem-first indexing wins." That structure does three jobs at once: it satisfies the searcher immediately, it reads well as a featured snippet, and it survives being chunked by AI answer engines, which quote committed verdicts and skip hedges. The remaining page is evidence for readers who need convincing, not a runway.
Refusing to pick is the most common failure. "Both are great options depending on your needs" answers nothing and ranks accordingly. If the honest answer is conditional, state the condition — that is still a verdict.
The spec table is the product
The table is what the searcher came for; everything else is commentary. The excerpt from this site's Immich/PhotoPrism page:
| Immich | PhotoPrism | |
|---|---|---|
| Mobile app with auto-backup | Yes, iOS + Android | No first-party auto-backup |
| ML search | Faces, objects, CLIP | Faces, objects, CLIP |
| Idle RAM (measured, Docker) | ~1.2GB | ~800MB |
| Database | Postgres (required) | MariaDB or SQLite |
| License | AGPL-3.0 | AGPL-3.0 |
Rules that make a table earn its place: 6–10 rows, every one decision-relevant (drop rows where the products tie unless the tie itself is the news); measured values, not adjectives — "~1.2GB idle" beats "lightweight" in credibility and in long-tail matching; and always include rows the overall loser wins. A sweep reads as marketing, and readers pogo back to the SERP to find a page they trust.
One URL per pair
"Immich vs PhotoPrism", "PhotoPrism vs Immich", and "Immich or PhotoPrism" are one intent, and one intent gets one URL. The convention that scales: alphabetise slugs (immich-vs-photoprism, never the reverse as a separate page), and if a reversed URL ever existed, 301 it. Publishing both directions splits your inbound links across two pages that then compete with each other — self-cannibalisation with extra steps. The same discipline separates the pair page from the list page: "immich alternatives" is list intent, and its page should link to comparisons, not duplicate them. The broader family of these bugs is catalogued in canonical URL edge cases.
Title both orders anyway — a title like "Immich vs PhotoPrism: The 2026 Verdict" ranks fine for the reversed query without a second page.
Schema: mark up the things, not the comparison
No "comparison" rich result exists, so don't invent markup for one. What works: an ItemList wrapping two SoftwareApplication entities with honest ratings — which is what renders stars — following the patterns in JSON-LD that moves the needle. FAQPage markup no longer produces a rich result for ordinary sites, but the question-and-answer content itself still earns People-Also-Ask appearances and AI citations, so keep the content and skip the markup.
Answer the follow-up questions on the page
Every comparison query trails a cloud of follow-ups: "can Immich import from PhotoPrism", "which needs less RAM", "does PhotoPrism have a mobile app". Answer each in 80 words or less, answer-first, under its own heading near the end of the page. These sections are cheap to template from structured data, they match the People-Also-Ask boxes almost verbatim, and they are the most-quoted part of the page in AI answers.
The human layer on head pairs
A template covers 40,000 pairs; editorial judgement covers the 500 that carry real volume. For those, hand-write the verdict, note the migration path, and pin claims to versions and dates ("as of Immich v1.13x") rather than "currently" — a dated claim ages into history; an undated one ages into a lie. This split — template for coverage, humans for the head — is the core economics of the programmatic SEO playbook, and comparison pages are where it pays most visibly.
Re-verify head pages quarterly. Comparison content rots at the speed of the faster-moving project, and a table that says a product lacks a feature it shipped last spring converts your credibility into their support tickets.
Comparison pages live or die on inbound links
A comparison page has two natural parents — both entity pages — and a grandparent in the category hub. Link from all three, every time, mechanically from the template. On this site each app page links to up to 25 of its comparisons and each comparison links back to both apps; that closed loop is what gets a page for a pair of mid-tail apps crawled at all. A comparison page published without inbound links is a page you chose not to index.
What I'd do
Template the skeleton: verdict paragraph, 6–10 row measured spec table, follow-up answers, ItemList schema, alphabetised slug with the reverse redirected. Generate wide, then hand-write verdicts for every pair with demonstrated impressions in Search Console. Re-verify the head quarterly, and let the long tail ride the template. A comparison page is a decision delivered with evidence — build the template around the decision and the rankings follow.