Packaging NestJS Modules for NPM Installs

We've been using NestJS for a long time at Entrostat, and we've found that there is base functionality that we like to share between projects. Some of this functionality is specific to our company, so it's not as simple as running npm install --save [package name]... or is it?

This article runs through the creation of a NestJS module that you can install and import into your project and start using it in the same way that you'd use any other npm installs. I've also added a more advanced example when you need to inject a service that needs configuration options because I didn't see that in the official docs.

The Scenarios

For the simple example, I'm going to create a Random Number module where it provides a service that returns a random number between x and y (specified on the initialisation of the module).

Once that example has been implemented, I'm going to make a more advanced example where I send in parameters that are used in a second service that reuses the first service but modifies the output. In this more advanced example, I'm going to show how to construct a service that requires dependency injection and additional configuration options that cannot be injected in.

Random Number Module

Let's create a new project from scratch and run through the structure from scratch,

A tsconfig.json file has been created in your root directory, paste the following json data into the file,

Now that the project has been created and configured, let's create a src folder and add our files,

Cool, so let's add code to each of these files,

You're now nearly ready to publish your first npm package! We just need to edit our package.json to make sure that the library gets pushed to the right place,

Now if you run npm run build, it should create a dist folder with a number of .js files in it.

You're ready to publish :)!!! So the next step is to log in to npm using the npm login command and after that run npm publish.

Installing and Using Your Module

Now that the new nestrand module has been created on npm, we can import it into an existing application and use it, imagine we're editing an AppModule in another project. We'd first run npm install --save nestrand and once that's added our import would look as follows,

It's as easy as that, you can now inject the RandomNumberService into any of your services and controllers and call the generate() function.

The More Advanced Example

The above example is quite simple because the RandomNumberService does not require any dependency injection, so it was easy to make in the forRoot(...) function in the module. However, what do we do when a service does require dependency injection as well as configuration options?

We're going to modify the project a bit to make this example work. Let's add a Logger service to the RandomNumberService,

Okay so we need to pass the Logger service into the RandomNumberService when we call the forRoot function, but where do we get the Logger from?

We can use a factory to create and inject the correct services and we can wrap the factory in a function to add additional options during runtime,

So here you can see that calling the function randomNumberServiceFactory returns a factory that creates the RandomNumberService, but it constructs the service with the options object. When the module is initialised, the service is created using these options, and everything works as expected.

Conclusion

I hope this shows everything you need to know around creating a NestJS module and publishing it to npm. The simple example has covered all of the details around publishing the package and the configurations required. The advanced example should also help you when you're in a jam where you'd like to initialise services with certain configuration values, but they also require dependency injection.

So get publishing :)!

Side Note

There are existing projects out there that you can use to start developing faster and more efficiently! Take a look at https://github.com/nestjsx/package-starter for a great example. Once you understand the example I gave, I'd suggest that you use this package starter because they've added a lot of additional functionality that is very useful.