Pages, variants and versions
You declare in code what can change on each page you route. This page explains how to shape that declaration, how everything in it is named, and what RoutingCat records as a version, so you can predict what a change in code will do. Build a page shows the code in full.
Choose a shape
A page is one page of your site, declared with its routes. A slot is a place on it that can change, and a variant is one alternative for a slot. Routing picks one variant per slot for each visit.
Give each idea the shape it needs:
| Shape | Use it for | Example |
|---|---|---|
| One slot | One thing to try | Three headlines for home/hero |
| Several slots | Things that can vary separately and still read well together | A headline and a call to action |
| One slot whose variants each hold several pieces | Pieces that must change together | A headline and the line under it, written as pairs |
Every combination must read well. Slots vary independently, so a visitor can get any headline with any line under it: 3 headlines and 2 lines make 6 combinations, and each must read well. Routing also judges each slot’s variants by their own effect: it doesn’t learn that a headline works only beside a particular line. So when pieces must match, put them in one slot, as parts of the same variant.
Combinations have no limit of their own, since no page is built once per combination: a page that carries every variant holds them all in one HTML, the same for every visitor, and each hidden variant adds to its weight. Limits and defaults gives the limits on slots and variants.
Defaults, keys and addresses
Every slot has a default: the variant your site shows today. The control always sees it, and the page shows it whenever RoutingCat doesn’t pick, as in development. A default can’t be paused or retired; promote another variant first.
Keys name pages, slots and variants: lowercase letters, digits, - and _, at most 40 characters. A variant’s history, scorecards and evidence belong to its key, not to its content. A retired key stays reserved: declaring it again brings back the retired variant, history included. So a new idea always gets a new key.
Addresses join the keys, and the commands take them:
| Address | Names |
|---|---|
home |
A page |
home/hero |
A slot |
home/hero:oneclick |
A variant, at its current version |
home/hero:oneclick@v2 |
One version of that variant |
A version can also be named by the start of its content hash, as home/hero:oneclick@7f3a1c; show prints the hash beside the version.
What makes a version
A version is one state of a variant’s content. The build registers a new one when a deploy carries content that differs from the variant’s current version. Versions are numbered @v1, @v2 and so on, and every version is kept.
What counts as content is a variant’s fields and the images they reference. Your page’s template and shared code make no version, since they change every variant of the slot alike, and neither do formatting or comments. A slot’s renderer schema belongs to the slot: changing it, or upgrading the library that writes it, such as Zod, leaves every variant’s version as it is. An image referenced by URL is identified by its URL, so new bytes at the same URL make no version.
An upgrade of routingcat that changes how a version is identified keeps your versions: the first deploy after it finds each variant’s version under its new identity, and makes none.
Same key or new key
The key decides what a change is compared with in its scorecard:
| Change | Key | Result | Its scorecard compares |
|---|---|---|---|
| A fix or a refinement | The same key | A new version of the variant | The new version with the one it replaced, over their own periods |
| A new idea | A new key | A new variant | The variant with the slot’s default, at the same time |
A comparison at the same time is the fair one: both sides meet the same visitors, days and campaigns. A before-and-after comparison can’t separate the edit from whatever else changed meanwhile. So edit under the same key to fix or polish an idea, and put a different idea under a new key. Routing treats them differently too: an edit builds on what the variant showed, while a new variant starts cautiously.
Deleting a variant from your code retires it at the next production deploy, keeping its history.
Parents
A new variant can declare where it came from, with parent and relation: fix, refine or fork for one parent, recombine for several. A parent is a variant of the same slot, by key or at a version, as current@v2.
The relation is recorded in the variant’s history, and show lists each version’s parents. One parent declared as a fix, a refinement or a fork also gives the new variant a head start: it begins from part of what its parent showed, never all of it, and show says its signal “borrows from” that parent. A recombination starts fresh. An edit under the same key always builds on the version before it, declared or not.
What isn’t captured
A version records only what you declare, and show lists, for each version, what it doesn’t capture: shared styles, behavior, data that depends on the request, third-party embeds, state that exists only in the browser, and content fetched at run time.
So a change to a shared stylesheet, or to a price fetched when the page renders, makes no version and opens no scorecard. Each deploy’s commit still records it.