> From the [Strife developer docs](https://strife.app/docs/reference/database/index-url). Every page is listed in [llms.txt](https://strife.app/docs/llms.txt).

# Index URL

`Content/ByUrl` is the content index your site queries. It is deployed by [`strife push`](https://strife.app/docs/reference/cli/commands.md#strife-push) and projects every content document into one row per configured locale, with `url` resolved from the document's origin chain — the row your site looks up by `url`, `docId` or `collection`.

## Row roles

Besides a document's published version, its working-copy siblings are indexed too. Every row carries a `status` that says which one it is, and the legacy `draft` boolean is kept during the deprecation window so older SDK builds keep matching:

| Row | `status` | `draft` | Notes |
| --- | --- | --- | --- |
| Published document | `published` | `false` | The only rows a public query should return. |
| Unpublished document | `unpublished` | `false` | Never had a published version. |
| `{id}/draft` | `draft` | `true` | The working copy. |
| `{id}/scheduled` | `scheduled` | `true` | A publish scheduled for later. |
| `{id}/snapshot/{token}` | `snapshot` | `true` | A snapshot — see below. |

A public query filters on `status == "published"` (or the legacy `draft == false`); sibling rows never match it. Soft-deleted and archived documents emit no row.

## Snapshot rows

A [snapshot](https://strife.app/docs/reference/snapshots.md) freezes a document's draft into a snapshot, `{id}/snapshot/{token}`, in the document's own collection. The index detects it by the id segment or by `status == "snapshot"`, folds it into the sibling flag (so `draft: true`), and emits **one row per locale in the snapshot** whose `url` **is the snapshot path** — the origin-chain root's slug for that locale (empty for a root slug `/`; built even for `disableURL` templates), then `/snapshot/{token}` — so every language is reachable through the link and an ordinary exact-URL lookup resolves the snapshot. Four stored fields exist for these rows and are `null` on every other row, so the field shape is uniform:

| Field | Snapshot row | Every other row |
| --- | --- | --- |
| `snapshotToken` | The token from the id — 8 lowercase letters or digits | `null` |
| `snapshotName` | The editor-given name, or the server's "Preview N" fallback; plain text, never HTML | `null` |
| `expiresAt` | UTC round-trip string ending in `Z` (`2026-09-04T09:30:00.0000000Z`) | `null` |
| `snapshotLocale` | The locale the editor was viewing when sharing — the one the link targets | `null` |

A site resolves a snapshot either by its ordinary **exact-URL lookup** (`url` + locale, admitting `status == "snapshot"` on exact-URL matches only — see [Snapshots](https://strife.app/docs/reference/snapshots.md)) or with **exact equality on `snapshotToken`** plus `status == "snapshot"` plus the resolved locale (the SDK path, which also checks `expiresAt` on every read). A soft-deleted snapshot (expired, revoked, or cascaded from an archive or delete) emits no row, which is what ends the link on the raw path. `deleted` is not stored; project it and treat `true` as a miss.

> [!NOTE]
> `snapshotToken` doubles as the index **version marker**. Strife refuses to create a snapshot for a team whose deployed `Content/ByUrl` definition does not emit it, and `strife push` refuses to deploy a source without it while the team holds an active snapshot — a definition without the field would map a snapshot as a public row at the canonical URL. Update `@strifeapp/strife` to the release that ships snapshots and push.

These field names are deliberately **not** reserved root fields: reserving `expiresAt` would silently drop a template field of that name from every public row on the next push. Avoid naming your own template fields `snapshotToken`, `snapshotName`, `expiresAt` or `snapshotLocale` all the same, so a snapshot row and a public row never disagree about what the field means.
