Routing
Controlling your storefront URLs
You want your product pages at /products/blue-sneaker, your categories at /shop/shoes, and your home page at /. In Laioutr, routing is driven by page types. Instead of manually creating route files, you define page types with URL patterns, and the platform generates all routes at build time from the pages configured in Studio.
This page explains how that process works and how you can customize it.
How routes are generated
Every page in your project is stored in laioutrrc.json as an RC page. Each RC page has a type field that references a page type token (e.g. ecommerce/product-detail-page) and a path that defines its URL.
At build time, Laioutr reads all RC pages and generates Nuxt routes from them. The page type's metadata determines what route parameters are expected and what data queries run when the route is matched. You never write pages/ directory route files for Studio-managed pages — the platform handles this.
Default URL patterns
Page types declare their URL shape through pathConstraints. When a content manager creates a new page of a given type in Studio, the default path is suggested automatically. Common defaults from built-in apps:
| Page type | Default pattern | Example URL |
|---|---|---|
| Home | / | / |
| Product Detail (PDP) | /products/:slug+ | /products/blue-sneaker |
| Product Listing (PLP) | /categories/:slug+ | /categories/shoes |
| Search Results | /search | /search?q=sneaker |
| Content Page | /pages/:slug+ | /pages/about-us |
| Landing Page | (custom per page) | /summer-sale |
The :slug+ syntax means the slug can contain multiple segments (e.g. /categories/men/shoes). This is standard Nuxt dynamic route syntax.
Customizing URL patterns
You control URL patterns by setting pathConstraints on your page type token:
export const ProductDetailPage = definePageTypeToken('ecommerce/product-detail-page', {
kind: 'dynamic',
pathConstraints: {
requiredParams: ['slug'],
default: '/shop/product/:slug+',
},
// ...
})
The three options inside pathConstraints are:
exact— a fixed path with no parameters. Use this for pages like Home (/) or a single search page (/search).default— the path pattern Studio suggests when a content manager adds a new page of this type. Content managers can override it per page.requiredParams— parameter names that must appear in the path. Studio validates that any custom path a content manager enters includes these parameters.
pathConstraints, the platform derives a path from the page type name and any required parameters. Explicit constraints give you full control over your URL structure.Static vs. dynamic page types
The page type's kind affects routing behaviour:
Dynamic page types (e.g. Product Detail, Category Listing) typically have one page definition that matches many URLs via route parameters. A single Product Detail page with path /products/:slug+ handles every product URL. The :slug parameter is extracted from the URL and passed to the page's data queries.
Static page types (e.g. Landing Page, Content Page) produce one route per page. Each page has its own fixed path set in Studio. A landing page at /summer-sale is a distinct route from another at /black-friday.
// Dynamic: one page handles all product URLs
definePageTypeToken('ecommerce/product-detail-page', {
kind: 'dynamic',
pathConstraints: { requiredParams: ['slug'], default: '/products/:slug+' },
// ...
})
// Static: each page gets its own unique path
definePageTypeToken('my-app/landing-page', {
kind: 'static',
studio: { label: 'Landing Page', group: 'Marketing', icon: 'megaphone' },
})
For more detail on defining page types, see the Page Types documentation.
How markets affect routing
When your project serves multiple markets, routing gains an extra layer. Each market has one or more domains, and each domain can have a path prefix for a specific language.
The resolution flow is:
- Domain matching — the request's hostname determines the market (e.g.
www.shop.chresolves to Switzerland,www.shop.deresolves to Germany). - Path prefix matching — if the domain has a path prefix for a language (e.g.
/frfor French), it is stripped before page type matching. - Page type matching — the remaining path is matched against the generated routes.
This means the same page type can produce different URLs per market:
| Market | Domain | Language prefix | Full URL |
|---|---|---|---|
| Switzerland | www.shop.ch | (none, German default) | www.shop.ch/products/sneaker |
| Switzerland | www.shop.ch | /fr | www.shop.ch/fr/products/sneaker |
| Germany | www.shop.de | (none) | www.shop.de/products/sneaker |
Pages can also be scoped to specific markets via marketIds in Studio. A page limited to the Switzerland market will not generate routes on www.shop.de. See Multi-market for configuration details.
Trailing slashes
Every storefront URL is generated in one shape, controlled by trailingSlash in the config block of your project's laioutrrc.json. It defaults to false, meaning URLs are generated without a trailing slash (/products/sneaker). Set it to true to generate them with one (/products/sneaker/).
{
"config": {
"trailingSlash": false
}
}
The policy is applied everywhere a URL is produced, so the shape stays consistent across the whole storefront:
| Surface | Effect |
|---|---|
| Generated routes | Page-type routes are registered in the configured shape. |
| Canonical and hreflang links | <link rel="canonical"> and every hreflang alternate use the configured shape. |
| Switch-locale and switch-market URLs | The language switcher and market switcher emit matching hrefs. |
useMarketPath | Returns paths in the configured shape. |
<NuxtLink> | Nuxt's link default is set to match, so client-side navigation hrefs agree with server-rendered ones. |
Normalizing incoming requests
A Nitro server middleware issues a 301 redirect for any request arriving in the opposite shape, so a URL is only ever served at one address. This runs before your project redirects, so a redirect rule always sees the path in its normalized shape.
Three kinds of path are left untouched:
- The root path
/. - Internal routes — anything under
/api/or starting with/_. - File-like paths, where the last segment contains a dot. This is what stops append-mode from turning
/style.cssinto/style.css/.
Path prefixes
Domain path prefixes are normalized before they are composed into a URL, so single-segment (/fr) and multi-segment (/en/us) prefixes both compose correctly — including prefixes written with a stray trailing slash. On a path-prefixed domain, the homepage resolves at /fr rather than /fr/.
Reading the policy at runtime
The active value is exposed on the public runtime config, so app and component code can generate matching URLs:
const { trailingSlash } = useRuntimeConfig().public.laioutr;
Path validation in Studio
Studio uses the page type's pathConstraints to validate paths that content managers enter. If a page type declares requiredParams: ['slug'], Studio will not allow saving a path like /products — it must include :slug (e.g. /products/:slug).
This prevents broken routes where a dynamic page type expects a parameter that the URL does not provide. The default path is pre-filled when adding a new page, so content managers only need to change it if they want a custom URL structure.
Redirects and routing
Laioutr's routing system generates routes from page types, but you may also need to handle old URLs, campaign short-links, or structural URL migrations. These are covered by Nuxt's redirect mechanisms. See Redirects for the full guide.
For information on how URLs work across languages, including the language switcher and localized slugs, see Multi-language support.
Redirects
How Laioutr applies project redirects on the live site, with exact and pattern matching, permanent and temporary status codes, and query-string forwarding.
Server-Side Rendering (SSR) and Caching
How the Laioutr frontend uses SSR, how to enable CDN caching with route rules, and how to handle multi-market setups and personalized content.