Originally published at coreycleary.me. This is a cross-post from my content blog. I publish new content every week or two, and you can sign up to my newsletter if you'd like to receive my articles directly to your inbox! I also regularly send cheatsheets, links to great tutorials by other developers, and other freebies!
Developers constantly ask things and express pain like:
"What's eating away at us is which modules to choose..."
"What is the difference between X module and Y module and which one is better?"
"npm is great but those modules might be useless in 6 months, a year or later depending on how they're supported."
Usually when asking such questions, you'll get ten different answers. And then everyone gives you their own favorite pet module and the rest of the thread is people arguing over which one is the best.
It's easy to face "analysis paralysis" when choosing npm modules. With so many to choose from, and new ones being touted as "what you really should switch to" it can be overwhelming to pick the right one for your project. And it doesn't help that so many of these modules do similar (or the same) things.
Rather than waste time Googling around, combing through npmjs.org, and wasting more time NOT building your application, it would be great to know which modules to choose when.
A curated list
In order to help combat this, below you'll find a list of modules for the most common types of problems (i.e. - web frameworks, templating, authentication, etc) and when to use each one.
There are a few caveats to this: you might be familiar with some or even many of these modules, but sometimes you're touching a part of the stack you haven't yet (maybe something like authentication or Web Sockets) and you need to know which modules will get the job done. You may have a module you think is better. You may have a use case/requirement not covered here. Rather than have a list of 10 different ones for the same category, I narrowed it down so that you can avoid the trap of analysis paralysis. By all means supplement this with research if you think you have a use case not covered, but this is designed to get you up and running much more quickly.
These modules were selected based on the following:
- how well they get the job done
- community size (important for support/troubleshooting)
- active maintenance
Note: in order to keep the scope reasonable, these modules are with the server-side in mind. Many can be used on the client or on the server, but this was approached "server-first".
- use when you need to make callback-based HTTP requests, i.e. from one REST service to another.
- use when you need to make promise-based HTTP requests
- note: you could use request-promise but axios has less dependencies and is built on native Promises
- use when you want a lightweight web framework for your API's, website, or single page app
- you don't mind using callbacks out-of-the-box for asynchronicity
- you want to be able to choose from a wide ecosystem of modules that work with the framework
- you want a large community for support and troubleshooting
- use when you want an even-more barebones framework than Express
- Koa is more of a middleware layer and doesn't provide templating or routing OOTB, making it better suited for API development
- you want async/await support OOTB
- use when you want a framework which has more "batteries" than Express or Koa, but not as much baked-in as Sails
- use when you want something like Rails, something that has everything baked-in (but a lot of which you might not need depending on your application)
- use when you need to validate JSON (like coming in from a web request)
- you want to share these schemas with other non-JS parts of the application (since it's JSON, you can do that)
- you're using Hapi (Joi comes with it OOTB)
- use when you need authentication middleware for your website or API
- you want to be able to choose between multiple authentication types (Oauth, Facebook, etc)
- you need to manage sessions
- use when you need to support an older version of Node that only supports callbacks, not Promises
ES6 native promises (native JS, not npm):
- use when you are working with a version of Node greater than 0.12
- another thing to consider is your team's level of comfort with Promises. In 2018, most developers should be.
async/await (native JS, not npm):
- use when you escaped callback hell only to discover Promise hell
- you've got lots of `.then` and `.catch` from Promises
The below is a mix of database drivers, ORM's and a query builder. Before you reach for the ORM, I'd highly suggest making sure you need to use one in the first place. Often they add another layer of abstraction that does not necessarily provide enough pay off, when you could just use raw SQL or a query builder.
- use when you don't need a full-on ORM, but instead are going to be querying your database with raw SQL (these are the drivers)
- use when you don't need a full-on ORM, but instead are going to be querying MongoDB directly
- use when you would rather use an ORM for MongoDB
- use when you don't need a full ORM solution but instead just need something to make writing queries in code easier
- Knex is a query builder which generates SQL
- you've got a Postgres, MSSQL, MySQL, MariaDB, SQLite3, Oracle, or Amazon Redshift database
- you want an ORM that supports everything Knex supports, doesn't use a query DSL (so what you're writing is closer to raw SQL), has a Promise-based API and good documentation
A helpful resource in comparing some process managers is http://strong-pm.io/compare. Note: they also include StrongLoop Process Manager, which is good but a bit hefty. I'd recommend checking out the solutions before first before deciding you're going to reach for StrongLoop's.
- use when you want a process manager that will handle restarting a service if it crashes and allow you to control clustering
- note: there is some haziness around potential violations of the AGPL license that PM2 is licensed under. There is some discussion on this here. My take is it's most likely ok to use. but check with your legal department if you have questions/concerns as I'm not a lawyer.
- use when you want a process manager that will handle restarting a service if it crashes
- you've got a smaller deployment (pm2, with its clustering support, is for larger scale deployments). If you only have a handful of services/processes, you're probably fine using forever
- use when you want to monitor for any code changes in your application and automatically restart the server when developing locally
- great to use for development!
For Web Sockets, rather than include a list of different ones I'm just recommending primus. It supports all the major Web Sockets implementations, is actively supported, and you can easily swap in and out different libraries with a line of code change if it turns out you need a different one.
- use when you want Web Sockets but don't want to deal with being locked in to any particular Web Sockets implementation
- use when you need to document your REST API and be able to test requests against endpoints
- use when you need a JS utility library
- you use a lot of OOP
- use when you want to program in a more functional style using functional composition
- you want something like lodash but in the functional paradigm
- use when you need to parse, validate, manipulate, and display dates/time
- use when you need random, unique id's that are hard to crack
- use when you want to be able to switch between multiple versions of Node installed in your environment
- use when you need to be able to `mkdir` recursively, `rm -rf`, and other file system utilities that are missing in Node
- use when you need to send emails from Node
- use when you need to load environment variables from a .env file into `process.env`
- use when you want to build a CLI utility that takes all the arguments as flags on the command line
- use when you want to build an "interactive" CLI utility that takes options sequentially (similar to how when you run `npm init` and it asks you a series of questions to generate the package.json file)
- use when you need a logging library and need different log outputs
- use when you need a logging library and can deal with JSON being the only log output
- you want to have different loggers for different components, request, or functions (i.e. - these loggers might parse things differently)
- use when you're using Express and you want to log your HTTP requests
- note: this would be used in conjunction with something like Winston or Bunyan. Since it's middleware, it know how to handle the request and log it, but doesn't handle the transportation to a log output that Winston and Bunyan do.
Pug (formerly Jade):
- use when you need a server-side templating engine that is easy to read and has support for blocks OOTB for sublayouts
- your output is only HTML
- use when you need a server-side templating engine that fully uses JS and is forgiving of whitespace indentation (Pug is not)
- note: does not support async JS functions though
- use when you need to write and run unit tests
- use when you need a library to prove your assertions in your unit tests
- note: this would be used in conjunction with Mocha
- use when you want to prove your assertions on promises rather than putting the assertion in the
- use when you want to prove your assertions on promises rather than putting the assertion in the
- use when you need a mocking library for your tests
- use when you want to generate API documentation from your code and you're using newer versions of JS
- supports current versions of JS - targets `class` by default, so if you're using prototypes in your code, use JSdoc
- use when you want a code API documentation generator that supports ES6
- supports both classes and prototypes
- use when you need a linter to automatically find (and fix) syntax and code pattern issues in your code
Native Node debugging has enough baked in now that my recommendation is to use what's there. A couple years ago it was helpful to pull in some npm modules and you might have a specific use case that requires one, but now there's enough native support that it makes sense to leave out the extra dependencies if you're not doing anything too crazy with debugging.
Picking modules can be tough, but you just need some waypoints to figure it out. Use this guide to help you when you're wasting time deciding what to pick or don't even know where to start.
One last thing!