http://inchoo.net/magento-2/routing-in-magento-2/ on Magento 2 routing discusses the sequence of Routers: Base, CMS, UrlRewrite and finally Default Router.
FrontController::dispatch loops through these Routers, calling their match() method.
Normally route matching patterns are defined in routes.xml files associated with each module. However, the home page route is not found in any of those. Instead, it's handled as a special case, as follows.
The following process recognizes the home page empty path, and translates that to a data structure consisting of 3 elements: moduleFrontName, actionPath, actionName, which end up being 'cms', 'index', 'index', or 'cms_index_index' when composed as a page_type id.
magento/framework/App/Router/Base.php:
public function match(\Magento\Framework\App\RequestInterface $request)
{
$params = $this->parseRequest($request); // Detects empty path, puts 'cms' for moduleFrontName in $params
return $this->matchAction($request, $params); // Uses default
}
protected function parseRequest(\Magento\Framework\App\RequestInterface $request)
{
$output = [];
$path = trim($request->getPathInfo(), '/');
$params = explode('/', $path ? $path : $this->pathConfig->getDefaultPath()); // fills in 'cms'
...
}
protected function matchAction(\Magento\Framework\App\RequestInterface $request, array $params)
{
...
$actionPath = $this->matchActionPath($request, $params['actionPath']); // calls defaultPath->getPart('actionPath'), fills in 'index'
$action = $request->getActionName() ?: ($params['actionName'] ?: $this->_defaultPath->getPart('action')); // fills in 'index'
...
}
magento/module-store/Model/PathConfig.php:
public function getDefaultPath()
{
// gets the value set for Stores > Configuration > [scope ] > Web > Default Pages > Default Web URL,
// which defaults to 'cms'.
return $this->scopeConfig->getValue('web/default/front', ScopeInterface::SCOPE_STORE);
}
As my added code comments note, the match($request) method calls parseRequest, in which an empty path causes a calls to scopeConfig->getValue for the value configured in admin for "Default Web URL", which is set to 'cms' in the default Magento 2 installation.
At that point in match(), only moduleFrontName has been determined. Next, match() calls matchAction($request, $params), which determines actionPath and actionName. for the home page case, each of these variables is determined from _defaultPath. And _defaultPath is dependency-injected when Router Base was originally instantiated from class DefaultPath. The class DefaultPath in turn gets that actual values for the parts of the path from dependency injection when constructed. I think this rabbit hole of dependency injection ends up at:
/app/etc/di.xml:
<preference for="Magento\Framework\App\DefaultPathInterface" type="Magento\Framework\App\DefaultPath\DefaultPath" />
...
<type name="Magento\Framework\App\DefaultPath\DefaultPath">
<arguments>
<argument name="parts" xsi:type="array">
<item name="module" xsi:type="string">core</item>
<item name="controller" xsi:type="string">index</item>
<item name="action" xsi:type="string">index</item>
</argument>
</arguments>
</type>
(Note: the getDefaultPath() in parseRequest() fetches path-related admin settings, while the _defaultPath object gets developer-set defaults.)
Summarizing this last part: _defaultPath ultimately gets an object instantiated by a factory that constructs a DefaultPath instance with defaults from di.xml. For our home page example, 'module' is not used (because the code already calculated aka moduleFrontName = 'cms'), and the values for 'controller' and 'action' provide values for $actionPath and $action.
The code having determined value 'cms_index_index', when control gets handed over to the cms module, its subsequent behavior is partly determined by corresponding values from module-cms/etc/frontend/page_types.xml and /module-cms/view/frontend/layout/cms_index_index.xml. (Beyond the scope of the current question.)
For what it's worth, I found the key clue about getDefaultPath() in Alan Storm's blog post on routing in Magento One: http://alanstorm.com/magento_dispatch_standard_router/.