Node.js supports the Dependency Injection (DI) design pattern by utilizing the awilix npm package. Awilix is a powerful dependency injection container for JavaScript/Node providing a very simple API.
Another useful package is awilix-express. This package provides helpers for awilix as well as router and scope-instantiating middleware for express.
Before proceeding with this article, ensure that you have node.js and visual studio code installed.
Getting started
Create a new project that handles e6+ features by using babel, and the visual studio code debugger. Read this article to set up the project. After setting up the project, install the below babel plugins to handle the decorator pattern and the async/await es6 feature.
npm install --save-dev @babel/plugin-proposal-decorators
npm install --save-dev @babel/plugin-transform-runtime
Modify the babel.config.json
file to include the new babel plugins.
Install the below dependencies for the project.
npm install awilix
npm install awilix-express
npm install body-parser
npm install compression
npm install cors
npm install express
The above setup is the basic configuration needed to get started with creating a RESTful API with node.js.
Creating app config
In the src
folder, create a new folder called app
. In the app
folder, create a new folder called configs
and add the following app.config.js
file.
Creating a heroes route
In the app
folder, create a new folder called routes
. In the routes
folder, create a new folder called heroes
with the below files.
From the above code base, it can be seen that the decorator pattern was used to create the controller. Also, a mock repository was created to get a list of heroes.
Creating the app
In the app
folder, create a file called app.js
with the below code.
The above class is standard for most express setups, with the exception of an additional two important middleware setups:
On line 31,
app.use(scopePerRequest(container));
the scopePerRequest
function creates a scope for each request.
On line 32,
app.use(loadControllers('routes/**/*.controller.js', {cwd: __dirname}));
the loadControllers
function loads all controllers in the routes
folder relative to the current working directory. This is a global pattern, thus new routes will automatically get registered.
Creating the DI container
In the app
folder, create a new file called bootstrap.js
with the below code.
The following is observed from the above code base.
On line 23,
const container = createContainer({injectionMode: InjectionMode.CLASSIC});
a new container is created using injectionMode.CLASSIC
. This mode indicates that the container is set to use constructor injection by parsing the function/constructor parameters, and matching them with registrations in the container. Note that awilix advises not to use this if the code base is going to be minified.
From lines 25 to 30,
container.register({
app: asClass(App).singleton(),
appConfig: asClass(AppConfig).singleton(),
heroesRepository: asClass(HeroesRepository).singleton(),
heroesService: asClass(HeroesService).singleton()
});
the container is been set up to indicate how a service is to be resolved, for example, whenever a heoresRepository
is requested, it is instantiated by a class called HeroesRepository
.
Awilix provides the following lifetime types.
- Transient: This is the default. The registration is resolved every time it is needed. This means that if a class is resolved more than once, then a new instance will be created every time.
- Scoped: The registration is scoped to the container meaning that the resolved value will be reused when resolved from the same scope.
- Singleton: The registration is always reused meaning that the resolved value is cached in the root container.
Creating the server.js file
In the src
folder, create a new file called server.js
with the below code. This file will be called whenever the application is started.
Run the application
Run the application by pressing F5
. Open postman and create a get
request to retrieve the mock heroes.

Summary
Awilix and awilix-express have made it very easy to set up a dependency injection container in a node.js project. This article was only an introduction to dependency injection with node.js. Awilix provides a lot more information to customizing a container based on the requirements of a project.
The source code used in this article can be found here.
Further information on dependency injection in node.js can be found at the following links.
Software versions used in this article
- node v12.17.0
- npm v6.14.5
- visual studio code v1.45.1
- babel v7.10.1
- awilix v4.2.6
- awilix-express v3.0.0
- postman v7.25.0