Hyvä Theme is Now Open Source: What This Means for Magento Community - Mageplaza
Hyvä is now Open Source and free. Discover what changed, what remains commercial, how it impacts the Magento ecosystem, and how to maximize its full potential.
Vinh Jacker | 03-17-2025
In this article, we will talk about how to create Magento 2 Routing. The Route will define name for a module which we can use in the url to find the module and execute the controller action.
In Magento 2, the reques url will be like this:
http://example.com/index.php/front_name/controller/action
In that url, you will see the front_name which will be use to find the module. The router define this name for each module by define in routes.xml which we will see more detail bellow.
When you make a request in Magento 2, it will follow this flow to find the controller/action:
index.php → HTTP app → FrontController → Routing → Controller processing → etc
The FrontController will be call in Http class to routing the request which will find the controller/action match.
File: vendor/magento/framework/App/FrontController.php
public function dispatch(RequestInterface $request)
{
\Magento\Framework\Profiler::start('routers_match');
$routingCycleCounter = 0;
$result = null;
while (!$request->isDispatched() && $routingCycleCounter++ < 100) {
/** @var \Magento\Framework\App\RouterInterface $router */
foreach ($this->_routerList as $router) {
try {
$actionInstance = $router->match($request);
if ($actionInstance) {
$request->setDispatched(true);
$this->response->setNoCacheHeaders();
if ($actionInstance instanceof \Magento\Framework\App\Action\AbstractAction) {
$result = $actionInstance->dispatch($request);
} else {
$result = $actionInstance->execute();
}
break;
}
} catch (\Magento\Framework\Exception\NotFoundException $e) {
$request->initForward();
$request->setActionName('noroute');
$request->setDispatched(false);
break;
}
}
}
\Magento\Framework\Profiler::stop('routers_match');
if ($routingCycleCounter > 100) {
throw new \LogicException('Front controller reached 100 router match iterations');
}
return $result;
}
As you can see in this dispatch() method, the router list will be loop to find the match one with this request. If it find out the controller action for this request, that action will be called and executed.
In web applications, such as Adobe Commerce and Magento Open Source, routing is the process of handling data from a URL request and directing it to the appropriate class for further processing. The flow of routing within Adobe Commerce and Magento Open Source follows this sequence: pub/index.php > application > front controller > routing > controller action.

In this part, we will use a simple module Mageplaza_HelloWorld. Please follow the previous article to know how to create Hello World Module in Magento 2.
We will find how to create a frontend route, admin route and how to use route to create controller.
To register a frontend route, we must create a routes.xml file:
File: app/code/Mageplaza/HelloWorld/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">
<!--Use router 'standard' for frontend route-->
<router id="standard">
<!--Define a custom route with id and frontName-->
<route frontName="helloworld" id="helloworld">
<!--The module which this route match to-->
<module name="Mageplaza_HelloWorld"/>
</route>
</router>
</config>
Please look into the code, you will see it’s very simple to register a route. You must use the standard router for the frontend. This route will have a child which define the module for it and 2 attributes:
<route frontName="helloworld" id="helloworld">
The url to this module should be:
http://example.com/index.php/helloworld/controller/action
And the layout handle for this action is: helloworld_controller_action.xml
So with this example path, you must create the action class in this folder: {namespace}/{module}/Controller/{Controller}/{Action}.php
This route will be same as the frontend route but you must declare it in adminhtml folder with router id is admin.
File: app/code/Mageplaza/HelloWorld/etc/adminhtml/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">
<!--Use router 'admin' for admin route -->
<router id="admin">
<!--Define a custom route with id and frontName -->
<route id="mageplaza_helloworld" frontName="mageplaza_helloworld">
<!--The module which this route match to-->
<module name="Mageplaza_HelloWorld"/>
</route>
</router>
</config>
The url of the admin page is the same structure with frontend page, but the admin_area name will be added before route_frontName to recognize this is a admin router. For example, the url of admin cms page:
http://example.com/index.php/admin/mageplaza_helloworld/controller/action
The controller action for admin page will be added inside of the folder Controller/Adminhtml. For example for above url:
{namespace}/{module}/Controller/Adminhtml/{Controller}/{Action}.php
In this path, we will see how to rewrite a controller with router. As above path, you can see each route will have an id attribute to identify. So what happen if we define 2 route with the same id attribute?
The answer is that the controller action will be find in both of that modules. Magento system provide the attribute before/after to config the module sort order which define what module controller will be find first. This’s the logic for the controller rewrite.
For example, if we want to rewrite the controller customer/account/login, we will define more route in the route.xml like this:
File: app/code/Mageplaza/HelloWorld/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">
<!--Use router 'standard' for frontend route-->
<router id="standard">
<!--Define a custom route with id and frontName-->
<route frontName="helloworld" id="helloworld">
<!--The module which this route match to-->
<module name="Mageplaza_HelloWorld"/>
</route>
<route id="customer">
<module name="Mageplaza_HelloWorld" before="Magento_Customer" />
</route>
</router>
</config>
And the controller file: app/code/Mageplaza/HelloWorld/Controller/Account/Login.php
So the frontController will find the Login action in our module first, if it’s found, it will run and the Login action of Magento_Customer will not be run. We are successful rewrite a controller.
You can also use this to have a second module with the same router as another module. For example, with above declare, you can use route ‘customer’ for your controller action. If you have controller ‘Blog’ and action ‘Index.php’ you can use this url:
Planning to make your module accessible via REST API? Learn how to create API in Magento 2 to extend your routing logic into full API integration.
http://example.com/customer/blog/index
If you got this error message: Exception printing is disabled by default for security reasons, this topic may help.