2 Ways to Improve your Node.js Application
Tags: node, devops, npm
Published: 2021-11-02 15:17:03

---
title: 2 Ways to Improve your Node.js Application
published: true
description: Improve your Node.js application with this two simple changes.
tags: node, devops, npm
//cover_image: https://direct_url_to_image.jpg
---
Use `npm ci --production`. Thanks for coming to my ted talk. 🎉

Kinda kidding, but not really.

For demonstration purposes, lets define a sample package.json, omitting some of the less important stuff.

```json
{
  "name": "test project",
  "version": 1.0.0,
  "description": "Our sample project",
  "dependencies": {
    "first-dep": "1.0.0"
  }
}
```

So let's say you've been hard at work on this "test project" all morning working with the "first-dep" library. Unfortunately for you, "first-dep" released a minor version the night before, going up to "1.1.0" and breaking one of the API's you use. You run your test suite locally and everything is as green as grass. You push your code and **egads batman** a bunch of tests are broken. You run your tests locally over and over again racking your brain for what's happening. So you push another change *just to see* and watch the integration environment break again. So as is common practice in Node, you delete your local dependencies, reinstall and **boom**. Tests are broken. *Finally.* Now you go to source control provider to look for what's changed and you see a single change in your package.json

```
-    "first-dep": "1.0.0",
+    "first-dep": "1.1.0",
```
The dreaded stealth patch. After some investigation, you discover that in your testing setup you run `npm install`. Causing the version to get modified in that environments package.json before it was changed in yours. Now you've come to a cross roads. *Typically* most updates your dependencies release don't directly affect your project and are fine to push through. But wait!

![There is another](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v59fq4qo8bwbrvtqjiq9.jpg)


`npm ci` stops this discussion dead in its tracks. Using *ci* over *install* in your build environments defends against this versioning mismatch. 
> (npm) will never write to package.json or any of the package-locks: installs are essentially frozen. [source](https://docs.npmjs.com/cli/v7/commands/npm-ci#description)

This brings us to the first usage improvement

1. Create highly reproducible builds of your dependencies

As long as you haven't specified dependency changes, there shouldn't be any in your automated environments.

What does this mean?

Typically, when you run the command `npm install`, you will have your dependencies installed, as well as some of your dependency versions updated if there are updates available. This can lead to some hard to find issues when running in an automated environment, similar to the one above.

2. Smaller production bundles

Going back to our example package.json. Lets say we want to add typescript to our workflow. First thing you'll want to do is `npm install typescript`. Now our package.json looks something like,
```json
"dependencies": {
  "first-dep": "1.0.0",
  "typescript": "^4.4.3"
}
```
But typescript isn't *required* to run our application. Typescript is a build tool. So even though we're only using it some of the time, it will be included in our node_modules every time. Irregardless of what command we use to set them up. To address this, we should pass the "-D" flag when installing packages that aren't required to run our application in production. So now our command should look like `npm install -D typescript`. Looking at our revised package.json, you should see something like,
```json
"dependencies": {
  "first-dep": "1.0.0",
},
"devDependencies": {
  "typescript": "^4.4.3"
}
```
Awesome! But... typescript still shows up in node_modules when you run `npm ci`. So it's great that we've started dividing our dependencies up between production and development, but the default behavior of *both* install commands is to install *all* dependencies. So we've got one more piece to this puzzle and that is the `--production` flag. This instructs npm that we want to ignore all of the packages listed in devDependencies.

So in short, if you're running your application in an automated environment (shared development servers, production, testing) make sure you setup your dependencies with the command `npm ci --production`. And while you're working any time you install a dependency that is not directly required by your app, install it with the "-D" flag.

---
Find me on [Twitter](https://twitter.com/therealdakotal) | [LinkedIn](https://www.linkedin.com/in/dakota-lewallen/)

Sponsor me on [Github](https://github.com/iamflowz)

Like the article? [Buy me a coffee!](https://www.buymeacoffee.com/iamflowz)