---
title: "Defining routes for Extbase plugins"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:extbase-routing-routes@main"
source: "ExtensionArchitecture/Extbase/Routing/Routes.rst"
rendered: "2026-09-24T12:36:55+00:00"
---

# Defining routes for Extbase plugins {#extbase-routing-routes}

Each entry in the `routes` list of the
[Extbase plugin enhancer](https://docs.typo3.org/permalink/t3coreapi:extbase-routing-enhancer@main) maps one
controller/action combination to a URL pattern. TYPO3 tries each entry in
order — first match wins, both for incoming requests and for URL generation.

> [!NOTE]
> **See also**
>
> [Route Enhancements and Aspects — route configuration keys](https://docs.typo3.org/permalink/t3coreapi:routing-advanced-routing-configuration-enhancers@main) —
> full reference for `defaults`, `requirements`, `static`, and `_arguments`.

## Anatomy of a route entry {#extbase-routing-routes-anatomy}

**EXT:my_extension/Configuration/Sets/MyExtension/route-enhancers.yaml**

```yaml
routes:
  - routePath: '/{conference_slug}'
    _controller: 'Conference::show'
    _arguments:
      conference_slug: conference
```

-   **`routePath`**

    The URL segment appended to the page slug. Static text and
    `{placeholder}` variables can be combined freely. A bare `/` matches
    the page URL with nothing appended — useful for the default action.

-   **`_controller`**

    The controller/action pair in `ControllerName::actionName` format —
    no `Action` suffix, no namespace. This tells TYPO3 which route to pick
    when generating a URL for that action, and which action to dispatch to
    when resolving an incoming request.

-   **`_arguments`**

    Maps placeholder names in `routePath` to Extbase argument names. In the
    example above, the URL segment captured by `{conference_slug}` is passed
    to the action as the argument named `conference`. The action receives the
    raw URL value — typically a slug string like `typo3camp-2025`. An
    [aspect](https://docs.typo3.org/permalink/t3coreapi:extbase-routing-aspects@main) on `conference_slug` then
    translates that slug into the UID that Extbase uses to load the object.
    Without an aspect the raw string reaches the action unchanged.

    Omit `_arguments` entirely when the placeholder name already matches the
    Extbase argument name.

## Route order and specificity {#extbase-routing-routes-order}

Routes are evaluated top to bottom. The first entry whose `routePath`
pattern and `_controller` both match wins. This means a general placeholder
route can accidentally swallow requests meant for a more specific route if it
appears first.

Consider a plugin with a list action, a paginated list, and a detail action.
Given the page slug `/conferences`, the following URLs need to resolve
correctly:

-   `/conferences/` → `Conference::list` (no arguments)
-   `/conferences/page/2` → `Conference::list` with `currentPage = 2`
-   `/conferences/typo3camp-2025` → `Conference::show` with the resolved UID

With this route order, resolution works correctly:

**EXT:my_extension/Configuration/Sets/MyExtension/route-enhancers.yaml**

```yaml
routes:
  - routePath: '/'
    _controller: 'Conference::list'
  - routePath: '/page/{page}'
    _controller: 'Conference::list'
    _arguments:
      page: currentPage
  - routePath: '/{conference_slug}'
    _controller: 'Conference::show'
    _arguments:
      conference_slug: conference
```

If `/{conference_slug}` were listed first, the request for
`/conferences/page/2` would match it — `conference_slug` would
receive the value `page` and the pagination route would never be reached.
The slug `typo3camp-2025` and the static segment `page` are both
just strings to the router; order is what distinguishes them.

## Making path segments optional with defaults {#extbase-routing-routes-defaults}

The `defaults` key at enhancer level makes a placeholder optional. When the
generated URL would contain the default value, that segment is omitted entirely.

In the full example below, `page: '1'` means a link to page 1 of the
list produces `/conferences/` rather than `/conferences/page/1`.
A link to page 2 still produces `/conferences/page/2`.

**EXT:my_extension/Configuration/Sets/MyExtension/route-enhancers.yaml**

```yaml
routeEnhancers:
  ConferencesPlugin:
    type: Extbase
    limitToPages:
      - 'page["module"] == "conferences"'
    extension: MyExtension
    plugin: Conferences
    defaultController: 'Conference::list'
    routes:
      - routePath: '/'
        _controller: 'Conference::list'
      - routePath: '/page/{page}'
        _controller: 'Conference::list'
        _arguments:
          page: currentPage
      - routePath: '/{conference_slug}'
        _controller: 'Conference::show'
        _arguments:
          conference_slug: conference
    defaults:
      page: '1'
    requirements:
      page: '\d+'
    aspects:
      page:
        type: StaticRangeMapper
        start: '1'
        end: '100'
      conference_slug:
        type: PersistedAliasMapper
        tableName: tx_myextension_domain_model_conference
        routeFieldName: slug

```

## Constraining placeholders with requirements {#extbase-routing-routes-requirements}

`requirements` defines a regular expression per placeholder. A route only
matches an incoming URL segment if it satisfies the requirement; without a
requirement, any string matches.

In the full example below, `page: '\d+'` ensures that
`/conferences/page/2` matches the pagination route while
`/conferences/typo3camp-2025` does not — because `typo3camp-2025`
is not all digits, so the pagination route is skipped and the detail route
matches instead.

Strict requirements also affect URL generation: combined with a
[StaticRangeMapper](https://docs.typo3.org/permalink/t3coreapi:extbase-routing-aspects-static-range@main) aspect, they
allow TYPO3 to treat the parameter as static and omit `cHash` from the
generated URL.

Note that `requirements` are ignored for any placeholder that has a
corresponding `aspects` entry — the aspect takes precedence.

**EXT:my_extension/Configuration/Sets/MyExtension/route-enhancers.yaml**

```yaml
routeEnhancers:
  ConferencesPlugin:
    type: Extbase
    limitToPages:
      - 'page["module"] == "conferences"'
    extension: MyExtension
    plugin: Conferences
    defaultController: 'Conference::list'
    routes:
      - routePath: '/'
        _controller: 'Conference::list'
      - routePath: '/page/{page}'
        _controller: 'Conference::list'
        _arguments:
          page: currentPage
      - routePath: '/{conference_slug}'
        _controller: 'Conference::show'
        _arguments:
          conference_slug: conference
    defaults:
      page: '1'
    requirements:
      page: '\d+'
    aspects:
      page:
        type: StaticRangeMapper
        start: '1'
        end: '100'
      conference_slug:
        type: PersistedAliasMapper
        tableName: tx_myextension_domain_model_conference
        routeFieldName: slug

```

The next step is configuring the `aspects` entries that translate
placeholder values into human-readable URL segments — see
[Routing aspects](https://docs.typo3.org/permalink/t3coreapi:extbase-routing-aspects@main).
