Every published page has exactly one live URL. Leed also keeps a record of every URL it has ever assigned that page, and serves a permanent redirect from each of them. That is the fact underneath everything on this page: you are free to rename, re-slug and reorganize, because the old addresses keep working.
You never type a URL in Leed. You set the pieces — a page type’s slug, a page’s slug, and for a documentation set, its folder position — and Leed composes the rest.
How a URL is composed
There are two shapes, and only two.
Ordinary page /{page-type-slug}/{page-slug}/
Documentation page /{page-type-slug}/{folder}/{folder}/{page-slug}/Every Leed URL composes with a trailing slash. An empty part is skipped rather than producing a doubled slash, and a page whose slug is empty composes to its section root — /docs/ — and publishes as that section’s index file.
The difference is the middle. A documentation page’s folder segments come from its position in its set’s left navigation menu, not from any field on the page. Each folder item’s name is slugified into one segment. Not its tooltip; not its title.
flowchart TD
UNIQ{"Is that path already taken<br/>by another page?"}
SUFFIX["Append -2, then -3, then -4 …"]
COMPOSE["Join the parts with slashes<br/>and add a trailing slash"]
OUT["/type/folder/slug/"]
subgraph ORD["An ordinary page"]
direction TB
OPT["Its page type's slug"]
OT["The page's title"] --> OS["slugified"]
end
subgraph DOC["A documentation page"]
direction TB
DPT["Its page type's slug"]
DF["Each ancestor folder's name<br/>in the left menu"] --> DFS["slugified, one segment each"]
DT["The page's title"] --> DS["slugified"]
end
OPT --> UNIQ
OS --> UNIQ
DPT --> UNIQ
DFS --> UNIQ
DS --> UNIQ
UNIQ -->|yes| SUFFIX
SUFFIX --> UNIQ
UNIQ -->|no| COMPOSE
COMPOSE --> OUT
The uniqueness check is a real loop: Leed keeps appending an incrementing suffix until the composed path is free across your whole workspace.
A page’s stored path value holds only the folder portion — never the page-type slug, never its own slug. For every non-documentation page type it is empty, because those sections are flat by design.
Where each slug comes from
| Segment | Source | Set where | Editable after publish? |
|---|---|---|---|
| Page-type slug | The page type’s own slug field | Settings → Page Types | No, once the section has published pages — the field goes read-only |
| Documentation folder segments | The name of each folder the page sits inside, in the set’s left menu, slugified | The Documentation section of the Design workspace | Yes — by moving the page or renaming the folder, which moves every page beneath it |
| Page slug | The page’s own slug, defaulted from its title | The editor’s Page settings tab, under Page Details | Yes, freely |
| Trailing slash | Always added | — | — |
How a slug is derived
At creation, a page’s slug is always the slugified title. Nothing else.
Slugification is not a straight lowercase-and-hyphenate. It splits runs of capitals, which produces results you would not predict from the title:
"Getting Started" → getting-started
"Pricing & Plans" → pricing-and-plans
"What is Leed?" → what-is-leed
"Importing an OpenAPI Spec" → importing-an-open-api-specThat last one is the one to remember. Check the slug after creating any page whose title contains an acronym, an ampersand or punctuation, and fix it before anything links to it — a link written against the wrong slug is an inbound URL you then have to keep redirecting.
If the composed path is already taken, Leed appends -2, then -3, and so on until it is free. This applies at creation and again every time you edit the slug, and it is silent — type a slug another page already owns and you get the suffixed version back with no message. Read the field after you type in it.
You cannot choose a page’s id either
A page’s id is minted by the server when the page is created and returned to you. It cannot be supplied — the create schema explicitly excludes it — and it never changes afterwards.
That id is what internal links and menu entries actually reference. A link written as pageid: plus an id resolves to whatever URL that page has at build time, which is why renaming a page never breaks a link inside Leed.
The practical consequence is for anyone importing content in bulk: the work is necessarily two passes. Create every page stub first, collect the ids that come back, and only then author bodies whose internal links point at them. A link written before its target exists cannot resolve, and at build time it renders as plain unlinked text rather than as an error.
The three kinds of path record
| Type | What it means | When it is created | What a visitor gets |
|---|---|---|---|
| Current | The page’s live URL | When the page is first published, and at every later publication | The page |
| Next | A reserved URL waiting to go live | The moment you change the slug of a published page, so nothing else can claim it before you publish | Nothing — it is a reservation, not a route |
| Alias | A URL the page used to have, or one you added by hand | When a slug change is published, or when you add a redirect | A permanent (301) redirect to the current URL |
Changing a slug safely
Renaming a published page is a four-step sequence, and only the last step is visible to the outside world.
- Edit the slug in the editor’s Page settings tab, under Page Details.
- The new URL is reserved immediately as a
nextrecord, so no other page can take it in the meantime. - Nothing changes on your live site. The page keeps serving at its current URL until you publish it.
- Publishing promotes the reservation. The
nextrecord becomescurrent, and the URL it replaced becomes analiasthat redirects permanently.
Change your mind before publishing and set the slug back to what it was, and the reservation is released — Leed notices the recomputed path matches the live one and deletes the next record.
There is no composed-URL preview beside the slug field. To see the full address a page will publish at, use Settings → URL paths & redirects, described at the end of this page.
When a slug change is refused
Only one thing hard-refuses a slug edit: a path that would sit exactly on another page type’s root. Try it and you get a 409 reading “Cannot place a page at ‘/docs/’ — that is the root path of the ‘Documentation’ page type”, naming the page type it collides with.
That rule is deliberately narrow. Overlap and nesting are fine. A page of your docs type parked at /docs/api/1.2.0/notes/ is allowed even when an API set roots at /docs/api/1.2.0/ — only landing exactly on that root is refused, because such a page would shadow the whole set’s landing address. A page at its own type’s root is also fine; that is how a section’s index page works. And a page type whose slug is empty — one that roots at the site root, like your homepage’s type — is exempt on both sides.
Everything else that looks like a collision is not refused, it is renumbered. Typing a slug another page already owns gives you the -2 form. That silence is worth naming, because it is the difference between the two ways a URL can change:
- Editing a slug de-duplicates silently.
- Moving a documentation page by dragging it in the menu refuses outright, with
409 "Cannot move page: the path '…' is already in use by another page". A folder move can relocate dozens of pages at once, so quietly renumbering some of them would be worse than stopping.
Moving a documentation page
State the rule before the mechanics, because this is the one most often broken by anyone creating pages programmatically:
A documentation page’s URL is its folder location in the left navigation menu, and the left menu is the only thing that sets it.
Each folder item’s name becomes one slugified segment. A path supplied when you create such a page is ignored by design, and the update endpoint does not accept a path at all — the code comment says why, and it is worth repeating: a path written straight onto the page record would not stage a matching URL row, so the CMS and the published site would immediately disagree about where the page lives.
So you relocate a documentation page by moving its menu item and saving the menu. Never by editing a field. Never by moving the file in your repository.
Getting that wrong is not a cosmetic problem. A page record whose stored path disagrees with its menu position breaks the paths table, the redirects generated from it, the sitemap, analytics continuity for the page, its breadcrumbs and its previous/next links — and can trip the database’s own uniqueness constraint on paths. Folders Set Your URLs covers the move itself, including what is staged versus committed when a folder rename relocates a whole subtree.
Where a page’s file lands in your repository
Every published page is a markdown file in your site repository, and its location mirrors its URL:
src/{page-type-slug}/{folder}/{folder}/{page-slug}.mdA page with an empty slug becomes index.md in its folder. Sidecar files — an API page’s OpenAPI document, for instance — sit beside the markdown with the same name and a different extension, so a move renames both together.
This is the same rule as the URL, stated from the repository side, and it is enforced rather than merely conventional: the page-type slug plus the folder path plus the page slug must equal the path derived from the file’s own location. The stored folder path is constrained to lowercase segments joined by single slashes, with no leading or trailing slash, and the import tooling throws outright when a documentation file does not sit under its page type’s slug root.
Useful to know if you read your repository. Mandatory if you write into it — see Your Site Repository.
Seeing every URL you own
Settings → URL paths & redirects, in the Content model group, is a read-only inventory of what Leed has composed for you. It has two sections, each with a count:
- Redirects — every alias row: the old URLs, still serving 301s.
- Permalinks — every live URL, sorted alphabetically, so nested documentation paths group under their sections.
There is nothing to edit here. Slugs are edited on the page, and redirects are added in the page’s own Redirects section — both in the editor’s Page settings tab.
A reserved URL becomes the live one at the page’s next publication — see Publishing and Scheduling a Page. What happens to the URL it replaced, and how to add a redirect deliberately for a migration or a memorable short path, is Aliases and Redirects.