# Routing & Sitemaps

> Source: https://agilitycms.com/docs/sveltekit/routing-sitemaps

In the [SvelteKit starter](https://github.com/agility/sveltekit-starter), **the Agility sitemap is the router**. Editors create pages (and their URLs) in Agility, and a single catch-all route renders whatever the sitemap says exists — no new route files when a page is added.

## The catch-all route

All CMS-driven pages flow through one route:

```
src/routes/
├─ +layout.server.ts     # resolves the Agility page for the current path
├─ +layout.svelte        # site chrome (header, footer)
└─ [...path]/
   ├─ +page.server.ts    # prerender config + entries()
   └─ +page.svelte       # picks the template and renders it
```

`[...path]` is a SvelteKit *rest parameter* — it matches `/`, `/about-us`, `/blog/my-post`, anything. The actual page lookup happens in the **layout load**, so the header and page resolve together:

```ts
// src/routes/+layout.server.ts
export const load: LayoutServerLoad = async ({ params, cookies }) => {
  const isPreviewMode = cookies.get('previewMode') === 'true';
  const isPreview = NODE_ENV === 'development' && isPreviewMode;
  const path = params.path || 'home';   // "/" falls back to the home page

  const { page } = await getAgilityPage({ path, isPreview });
  page.header = await getSiteHeader(isPreview);

  return { isPreview, page };
};
```

## Resolving a path against Agility

`getAgilityPage` asks the Content Fetch API for the page **by its sitemap path** — one call returns the sitemap node, the page, its zones, and (thanks to `contentLinkDepth: 4`) the content each component needs:

```ts
// src/lib/agility/getAgilityPage.ts
const api = agility.getApi({
  guid: AGILITY_GUID,
  apiKey: isPreview ? AGILITY_API_PREVIEW_KEY : AGILITY_API_FETCH_KEY,
  isPreview,
});

const page = await api.getPageByPath({
  pagePath: `/${path}`,
  locale: AGILITY_LOCALES,
  channelName: AGILITY_SITEMAP,
  contentLinkDepth: 4,
});

if (!page) error(404, 'Page not found.');
```

If the path isn't in the sitemap, the route 404s — editors deleting a page removes it from the site automatically.

## Prerendering every sitemap route

The starter prerenders the whole site at build time. `entries()` tells SvelteKit which paths exist by walking the **flat sitemap**:

```ts
// src/routes/[...path]/+page.server.ts
export async function entries() {
  const sitemap = await getSitemapFlat({ isPreview: false });
  return Object.keys(sitemap)
    .filter((key) => key !== '/home')      // "/" already covers home
    .map((key) => ({ path: key.slice(1) }));
}

export const prerender = true;
export const ssr = true;
```

> **Because pages are prerendered, a content publish requires a rebuild** to show up in production. Wire an Agility webhook to your host's build hook — see the deployment guides for [Vercel](/docs/sveltekit/deploying-to-vercel), [Netlify](/docs/sveltekit/deploying-to-netlify), [Azure](/docs/sveltekit/deploying-to-azure), and [AWS](/docs/sveltekit/deploying-to-aws). (You can also switch the route to pure SSR by removing `prerender` and caching responses — the [Astro starter docs](/docs/astro/how-the-astro-starter-works) show that pattern.)

## Picking the template

Back in the page component, the resolved page's `templateName` decides which Svelte layout template renders it, and `<svelte:head>` gets the SEO fields:

```svelte
<!-- src/routes/[...path]/+page.svelte -->
<svelte:head>
  <title>{`${sitemapNode.title} | ${title}`}</title>
  <meta name="description" content={seo.metaDescription} />
</svelte:head>

{#if templateName === "Main Template"}
  <MainTemplate {...data} />
{:else}
  Template not found.
{/if}
```

See [Pages](/docs/sveltekit/pages) for what happens inside the template, and [Components](/docs/sveltekit/components) for how each zone renders its components.

---

Index of every docs page: https://agilitycms.com/docs/llms.txt
