Skip to main content


A module clusters all rotes and binds relative to an scope or feature of the application and may contain sub modules forming one single composition. It means that to access a bind, it needs to be in a parent module that's already started, otherwise, the bind will not be visible to be recovered using a system injection. A Module’s lifetime ends when the last page is closed.

Routing between modules

The shelf_modular works with "dynamic routes”, segments, query, fragments, very similar to what we see on web. Let’s take a look at the anatomy of a “path”. To access a route within a submodule, we will need to consider the segments of the route path represented by URI (Uniform Resource Identifier). For example:


We call “segment” the text separated by /. For example, the URI /home/user/1 has three segment, being them [‘home’, ‘user’, ‘1’];

Use the Route.module builder to add a module to another:

class AModule extends Module {

List<ModularRoute> get routes => [
Route.get('/', () => Response.ok('path -> /')),
Route.module('/b-module', module: BModule()),

class BModule extends Module {

List<ModularRoute> get routes => [
Route.get('/', () => Response.ok('path -> /b-module/')),
Route.get('/other', () => Response.ok('path -> /b-module/other')),

In this scenario, there are two routes in AModule, a Route.get called / and a Route.module called /b-module.

The BModule contains another two Route.get called / and /other, respectively.

What would you call Route.get /other? The answer is in follow up. Assuming that AModule is the application’s root module, then the initial segment will be the name of the BModule, because we need to get a route that is within it.


The next segment will be the name of the route we want, the /other.


READY! When you execute the http://localhost:3000/b-module/other’) e verá a resposta: path -> /b-module/other.

The logic is the same when the submodule contains a route named as /. Understanding this, we assume that the available routes in this example are:

/                 =>  `path -> /` 
/b-module/ => 'path -> /b-module/'
/b-module/other => 'path -> /b-module/other'

When the concatenation of named routes takes place and generates a //, this route is normalized to /. This explains the first example of the session.


If there is a route called / in the submodule shelf_modular will understand it as “default” route, if no other segment is already placed after the module. For example:

/b-module => 'path -> /b-module/'

Same as:

/b-module/ => 'path -> /b-module/'

Module import

A module can be created only to store binds. A use case would be established when we have a Shared or Core Module containing all the main binds and distributed among all modules. To use a module only with binds, we must import it into a module containing routes. See the next example:

class CoreModule extends Module {

List<Bind> get binds => [
Bind.singleton((i) => HttpClient(), export: true),
Bind.singleton((i) => LocalStorage(), export: true),

class AppModule extends Module {

List<Module> get imports => [

Note that CoreModule binds are marked with the export flag export: true, this means that the bind can be imported into another module.


The module import is only for Binds. Routes won't be imported.