How Magento 2 Routing Works
Magento 2 uses a modular routing system that maps incoming HTTP requests to specific controller actions. Unlike Magento 1 which used a single front controller with rewrite rules, Magento 2 uses a chain of routers that attempt to match each request.
When a request enters Magento, the Magento\Framework\App\FrontController iterates through all registered router instances. Each router implements Magento\Framework\App\RouterInterface and has a match() method that receives the request and returns a matching action if found, or null to pass to the next router.
The routing flow:
- HTTP request hits
pub/index.php - Application creates
FrontController FrontController::dispatch()loops through routers- First router to return an action wins
- Action controller executes and returns a result
The router chain includes StandardRouter, UrlRewriteRouter, BaseUrlRouter, and any custom routers. The StandardRouter checks route definitions from routes.xml files across all modules.
Magento 2 introduced area-specific routing. Each area (frontend, adminhtml, webapi_rest) has its own set of routes defined in area-specific routes.xml files. This means the same module can define different controllers for the storefront and admin panel.
Route IDs and Front Names
Every route in Magento 2 has two key identifiers: a route ID and a front name.
The route ID is a unique identifier within the module's routes.xml. It's used internally to associate controllers with the route.
The front name appears in the URL and is used to match incoming requests. For example, in the URL catalog/product/view, catalog is the front name.
Example routes.xml configuration:
<!-- app/code/Vendor/Module/etc/frontend/routes.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="vendor_module" frontName="custompage">
<module name="Vendor_Module"/>
</route>
</router>
</config>
In this example:
vendor_moduleis the route ID (internal)custompageis the front name (appears in URL)- The module
Vendor_Moduleowns this route
A controller action at app/code/Vendor/Module/Controller/Index/Index.php would be accessible at custompage/index/index. The URL segments map to: {frontName}/{controller}/{action}.
Route IDs must be unique across the entire system to avoid conflicts. Front names must also be unique—if two modules define the same front name, Magento uses the module sequence order to determine which wins.
Router Classes and Matching
Magento 2 has several built-in router classes, each handling different types of requests:
StandardRouter (Magento\Framework\App\Router\StandardRouter): Handles standard module/controller/action routing by matching front names against routes.xml definitions.
UrlRewriteRouter (Magento\UrlRewrite\Controller\Router): Matches URL rewrite rules stored in the url_rewrite database table. This handles SEO-friendly URLs.
BaseUrlRouter (Magento\Framework\App\Router\BaseUrlRouter): Handles base URL detection and store switching.
DefaultRouter (Magento\Framework\App\Router\DefaultRouter): Catch-all router that handles CMS pages, 404 pages, and other default behaviors.
Custom router example:
<?php
namespace Vendor\Module\Controller\Router;
class CustomRouter implements \Magento\Framework\App\RouterInterface
{
public function match(\Magento\Framework\App\RequestInterface $request)
{
$pathInfo = $request->getPathInfo();
if (strpos($pathInfo, 'special/') === 0) {
$request->setRouteName('vendor_module');
$request->setControllerName('special');
$request->setActionName('view');
return $this->actionFactory->create(
\Magento\Framework\App\Action\Forward::class
);
}
return null;
}
}
Register custom router via di.xml:
<config>
<type name="Magento\Framework\App\FrontController">
<arguments>
<argument name="routers" xsi:type="array">
<item name="custom" xsi:type="object">Vendor\Module\Controller\Router\CustomRouter</item>
</argument>
</arguments>
</type>
</config>
Matching Front Controller Flow
Understanding the complete front controller flow helps debug routing issues and build custom routing logic.
The dispatch cycle in detail:
// Simplified Magento front controller dispatch
public function dispatch(RequestInterface $request)
{
$this->request = $request;
$result = null;
foreach ($this->routers as $router) {
$actionInstance = $router->match($request);
if ($actionInstance !== null) {
$this->requestedActionName = $request->getActionName();
$this->actionInstance = $actionInstance;
$result = $this->handleRouteNotAllowed($actionInstance, $request);
break;
}
}
if ($result === null) {
$request->initForward();
$request->setActionName('noroute');
$request->setControllerName('index');
$request->setRouteName('default');
$result = $this->dispatch($request);
}
return $result;
}
Route matching follows this sequence:
- Extract URL path info (e.g.,
catalog/product/view/id/5) - Parse into front name, controller, action, and params
- Each router attempts to match the front name
StandardRouterlooks up route definitions fromroutes.xml- If matched, instantiate the controller class
- Check ACL/permissions if needed
- Execute the
execute()method
You can observe routing by enabling debug logging or using the Magento\Framework\App\Router\DebuggingRouter in development. The class logs all router attempts and matches.
Quiz
1. What is the difference between a route ID and a front name in Magento 2?
2. Which router handles URL rewrite rules from the database?
3. What happens when no router matches a request?
Flashcards
Question
What interface must Magento 2 routers implement?
Click to reveal answer
Answer
Magento\Framework\App\RouterInterface with a match() method
Question
What XML file defines routes in a Magento 2 module?
Click to reveal answer
Answer
etc/frontend/routes.xml (or etc/adminhtml/routes.xml for admin)
Question
What is the URL format for standard Magento controller actions?
Click to reveal answer
Answer
{frontName}/{controllerName}/{actionName}
Question
Which component in the dispatch loop iterates through routers?
Click to reveal answer
Answer
FrontController::dispatch() loops through all registered routers
Revision Notes
Key Takeaways
- 1. Magento 2 uses a chain-of-responsibility pattern for routing
- 2. Each route has a route ID (internal) and front name (URL-visible)
- 3. Routes are defined in etc/{area}/routes.xml per module
- 4. The StandardRouter matches front names from routes.xml
- 5. Custom routers implement RouterInterface and are added via di.xml
- 6. When no router matches, Magento forwards to noroute action
Interview Tips
- • Be able to explain the full dispatch cycle from HTTP request to controller action
- • Know the difference between route ID and front name
- • Explain how to create a custom router and register it via DI
- • Describe the router priority order in Magento 2
- • Discuss why Magento 2 moved from rewrite rules to router classes
Cheat Sheet
Magento 2 Routing Cheat Sheet
Route config: etc/{area}/routes.xml
<router id="standard">
<route id="mymod" frontName="mypage">
<module name="Vendor_Module"/>
</route>
</router>
Router chain: StandardRouter → UrlRewriteRouter → BaseUrlRouter → DefaultRouter
Custom router registration: Add to FrontController routers argument via di.xml
Controller path: Controller/{controller}/{Action}.php
URL pattern: /{frontName}/{controller}/{action}