---
title: Content tree-based routing
related:
  - https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing/enable-content-tree-based-routing.md
  - https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing/set-up-content-tree-based-routing.md
  - https://docs.kentico.com/documentation/developers-and-admins/development/routing/configure-forbidden-url-characters.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

With content tree-based routing, the system generates and matches page URLs based on their position in the website's [content tree](https://docs.kentico.com/documentation/business-users/website-content.md). You don't need to perform any manual route mapping and configuration. All routing logic is handled for you by the system.

This method of routing is not a full replacement of the standard ASP.NET routing model. Instead, it augments the routing pipeline, handling requests targeting the site's pages. You can still set up [additional routes](https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing/set-up-content-tree-based-routing.md#combine-content-tree-based-and-asp.net-routing) for your application.

This simplified diagram models request handling when using content tree-based routing:

![Flowchart: a request enters the routing table, where the general system route registered with IEndpointRouteBuilder.Kentico().MapRoutes() precedes any site-specific routes. If the system matches the request, Xperience retrieves and serves the page. Otherwise, standard ASP.NET routing continues.](https://docs.kentico.com/docsassets/documentation/content-tree-based-routing/routing-request-handling.drawio.svg "Request handling in the content tree-based routing mode")

Incoming requests are matched against a general route and their target URL compared to system URLs and [vanity URLs](https://docs.kentico.com/documentation/business-users/website-content/manage-page-urls.md#edit-vanity-urls-of-pages) of existing pages. If there is a match with a route in the system (system or vanity URL), the system takes over the routing logic. Otherwise, the request continues matching against routes registered further down the routing table using conventional ASP.NET routing.

Once the request is taken over by Xperience, all routing happens automatically. You need to supply a controller, view model and view for each [content type](https://docs.kentico.com/documentation/developers-and-admins/development/content-types.md) to provide the desired processing logic and output formatting.

## Page URL generation

The system automatically generates URLs only for pages that have the _Include in routing_ option set in their [content type](https://docs.kentico.com/documentation/developers-and-admins/development/content-types.md) definition.

A page system URL is generated when:

- a new page is created
- the [URL slug](https://docs.kentico.com/documentation/business-users/website-content/manage-page-urls.md) of an existing page is updated

The overall system URL is determined by the page's location in the site's content tree:

- The system takes all of the page's ancestors up to the site's root ('/'):
  - If an ancestor has the _Include in routing_ option set for its content type, it contributes a segment to the page's resulting URL. All other ancestors are skipped.
  - By default, the segment is formed from the page's title converted to a URL-sanitized string.

The following diagram illustrates how URLs are generated based on a page's position in the content tree and the configuration of its ancestors:

![Content tree under the website root (/). The Articles page has the Include in routing option set and adds the segment Articles/, so its children Article 1 and Article 2 get the URLs \~/Articles/Article-1 and \~/Articles/Article-2. The Landing pages page doesn't have the option set and adds no segment, so its children Page 1 and Page 2 get the URLs \~/Page-1 and \~/Page-2.](https://docs.kentico.com/docsassets/documentation/content-tree-based-routing/routing-url-generation.drawio.svg "Automatic URL generation illustrated")

The _Articles_ section holds a collection of articles (_Article 1_ and _Article 2_). All pages are based on content types that have the _Include in routing_ option set. As a result, both articles also contain their parent page segment (_Articles_) in their URL.

The _Landing pages_ section holds a collection of landing pages (_Page 1_ and _Page 2_). Only the landing pages are based on a content type with the _Include in routing_ option set. As a result, the URLs of both landing pages do not include their parent.

### Home page and the site root URL

The site root ('/') itself is not a page. To determine which page is served when visitors access the channel's root URL (e.g., _https://example.com/_), select the page in the **Home page** setting of the website channel. The system then serves the page under the root URL and redirects the page's other URLs to it. You don't need custom routes or middleware to handle the site root – the **Home page** setting covers it.

See [Home page redirect and the website root URL](https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing/enable-content-tree-based-routing.md#home-page-redirect-and-the-website-root-url).

### Multilingual URLs

If you have multiple [languages](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md) set up in your project, the URLs follow the [format](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md#content-languages-and-channel-url-formats) selected during the channel creation.

| Language prefix                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Language-specific domains                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| All language variants of the page are served from the same domain<br>The URLs of pages that are in the [primary language of a website channel](https://docs.kentico.com/documentation/developers-and-admins/configuration/website-channel-management.md) are not modified.<br>For example, if English is set as the primary language of the website channel, the URLs of pages in _English_ will be in the `~/page` format.<br>For pages in a non-primary language, the language's **Code name** is inserted into the URL path after the site's root ('/').<br>For example, if English is set as the primary language of the website channel, the URLs of pages in _Spanish_ will be in the `~/es/page` format.<br>Vanity URLs of pages in a non-primary language DO NOT include the language's _Code name_.<br>Each vanity URL needs to be unique across languages<br>Regardless of the primary language of the website channel, the vanity URLs of pages in _Spanish_ will be in the `~/spanishVanityPath` format and in _English_ it will be in the `~/englishVanityPath` format. | Each language uses a different domain<br>URLs for different language variants of a page are differentiated by the domain and not in the URL path<br>System URLs and vanity URLs can use an identical URL path for different language variants of one page<br>Once a vanity URL is used for a page in one language, it can only be used for other language variants of the page. |
| [Vanity URLs](https://docs.kentico.com/documentation/business-users/website-content/manage-page-urls.md#edit-vanity-urls-of-pages) and the configurations of [canonical URLs](https://docs.kentico.com/documentation/business-users/website-content/manage-page-urls.md#select-the-canonical-url-of-pages) are completely separate for each language.<br>It is possible to set different [URL slugs](https://docs.kentico.com/documentation/business-users/website-content/manage-page-urls.md) for each language variant of the page.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |                                                                                                                                                                                                                                                                                                                                                                                 |

#### Language fallbacks in routing

When a request arrives, the system first determines the _requested language_:

- **Language prefix** format – if the first segment of the URL path matches the **Code name** of any content language, that language is requested. Otherwise, the primary language of the channel is requested, and the whole path (including the unmatched first segment) is matched against page URLs.
- **Language-specific domains** format – the language configured for the request's domain is requested.

The system then serves the page as follows:

1. If the page has a _published_ language variant in the requested language, that variant is served.
2. Otherwise, the system serves the first published variant found in the requested language's [fallback chain](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md#language-fallbacks). The fallback content is served under the URL of the requested language with the HTTP 200 status. The system does not redirect to the URL of the fallback language, and sets the request's culture according to the requested language.
3. If no language in the fallback chain has a published variant, the request results in the [HTTP 404 (Not Found)](https://en.wikipedia.org/wiki/HTTP_404) status. The chain contains only explicitly configured fallbacks. There is no automatic fallback to the default language or the channel's primary language.

![Flowchart: a page request in the requested language first checks whether the page is published in that language. If yes, the request returns HTTP 200. If not, the system checks each next language of the fallback chain in turn. The first language with a published variant returns HTTP 200, served under the URL of the requested language without a redirect. If no language is left in the chain, the request returns HTTP 404, with no automatic fallback to the default language or to the channel's primary language.](https://docs.kentico.com/docsassets/documentation/content-tree-based-routing/language-fallbacks-in-routing.drawio.svg "Language fallbacks in routing")

For example, a website channel uses the language prefix format with English (`en`) as its primary language. Spanish (`es`) falls back to English, German (`de`) has no fallback language, and a page is published only in English:

| Request                                                          | Status | Served content                                              | Request culture |
| ---------------------------------------------------------------- | ------ | ----------------------------------------------------------- | --------------- |
| `~/page`                                                         | 200    | English variant                                             | English         |
| `~/es/page`                                                      | 200    | English variant from the fallback chain, without a redirect | Spanish         |
| `~/de/page`                                                      | 404    | None, German has no fallback language                       | –               |
| `~/es/page` after a Spanish variant is created but not published | 200    | English variant, the Spanish _Draft_ is skipped             | Spanish         |

For more information about how fallbacks are resolved, see [Fallback resolution](https://docs.kentico.com/documentation/developers-and-admins/configuration/languages.md#fallback-resolution).

[Redirects](https://docs.kentico.com/documentation/business-users/website-content/edit-and-publish-pages.md#redirects-from-unpublished-and-deleted-pages) set when unpublishing or deleting a page variant take precedence over fallbacks.

## Handling of unpublished and deleted pages

When unpublishing or deleting a page, you can select how the requests for the page will be handled. Requests can be [redirected](https://docs.kentico.com/documentation/business-users/website-content/edit-and-publish-pages.md#redirects-from-unpublished-and-deleted-pages) to another page, or content in a fallback language can be served if available. Once a system URL is generated for a page, the URL persists until the corresponding page is deleted without a redirect.

If a request targets an unpublished or deleted page with no redirect and no fallback language variant, content tree-based routing does not match the request, and routing continues against other routes registered in the application. When no other route matches, ASP.NET Core responds with the [HTTP 404 (Not Found)](https://en.wikipedia.org/wiki/HTTP_404) status. To display a custom error page managed in the content tree, see [Serve custom error pages](https://docs.kentico.com/documentation/developers-and-admins/development/routing/serve-custom-error-pages.md).

## Configure your project to use content tree-based routing

To start using content tree-based routing in your project:

1. [Enable content tree-based routing](https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing/enable-content-tree-based-routing.md).
2. [Set up the routing environment](https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing/set-up-content-tree-based-routing.md).
