# Using pnpm for all package management for custom nodes

**URL:** <https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391>\
**Category:** Developing Nodes\
**Tags:** external-package\
**Created:** [30 January 2023 09:23 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391 "2023-01-30T09:23:52Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [30 January 2023 09:23 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/1 "2023-01-30T09:23:52Z")

</div>

In order to ship internal custom nodes to our users faster with smaller install size, we are trying out pnpm to replace npm in the context of NodeJS for Node-RED.

Although pnpm seems to be better than npm in terms of installation speed and size for NodeJS, we are not sure how that will turn out to be with Node-RED.

For one, I assume that pnpm will at least co-exist with npm, because community nodes are still installed using npm through Node-RED workspace which cannot be replaced without hacking NR internals, correct?

The scenarios where we want a drop-in replacement using pnpm for npm are roughly:

- `pnpm install -g node-red`
- under ~/.node-red, `pnpm install /path/to/my_custom_node`
- under `/path/to/my_custom_node`: `pnpm install`

Will NR remain working if we made such a drop-in change?  
Thanks!

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [30 January 2023 09:32 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/2 "2023-01-30T09:32:51Z")

</div>

First time I've heard of pnpm - so you are blazing the trail. You will have to rely on your own testing to ensure it is working as you need. Your feedback would be useful. (I can't see why it shouldn't work - just I have never seen/tested it)

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [30 January 2023 10:47 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/3 "2023-01-30T10:47:19Z")

</div>

Thanks for the input, @dceejay .  
Guess trial-and-error is inevitable then.

btw, [here](https://refine.dev/blog/pnpm-vs-npm-and-yarn/) is a comparison between pnpm, npm, and yarn.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [30 January 2023 11:39 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/4 "2023-01-30T11:39:30Z")

</div>

I'm pretty sure this will break uibuilder. It relies heavily on npm and needs to know where modules actually live in some cases in order to be able to make them available as web endpoints. That is hard enough just with npm itself but it looks like pnpm uses an entirely different structure.

Also, uibuilder, like Node-RED itself, assumes that npm will always be available. Since npm does not provide a stable API, you have to call it from an exec.

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [31 January 2023 03:23 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/5 "2023-01-31T03:23:40Z")

</div>

@TotallyInformation That's unfortunate.  
However, we will not remove npm but let it co-exist with pnpm. Will that work?

Our pain point:

- all the custom nodes share some dependencies,
- but we found no easy way to share those dependencies across nodes once they get registered into every `package.json`
- When shipping all the nodes to customer, the duplication either makes installer bigger or make installation longer

Is there any best practice regarding sharing dependencies across nodes?

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [31 January 2023 07:30 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/6 "2023-01-31T07:30:41Z")

</div>

> [@kakyoism](#):
>
> When shipping all the nodes to customer, the duplication either makes installer bigger or make installation longer

Did you already benchmark these topics?  
I would assume the difference is neglectable - if you intend to ship a single node as an independent unit:

- Each node needs it's environment to run, thus all dependencies have to be fulfilled - consequentially either made available online or offline. This is independent of the making of the package manager you use...
- Once a package is installed, `npm` doesn't install it a second time. The check for availability consumes almost no time...

If you ship all your nodes in a combined package, the situation is similar - and you can save some bytes only in case you make your dependencies available offline.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [31 January 2023 20:31 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/7 "2023-01-31T20:31:21Z")

</div>

> [@kakyoism](#):
>
> However, we will not remove npm but let it co-exist with pnpm. Will that work?

Perhaps. Needs testing.

One idea I've had for the future - since uibuilder does have quite a few dependencies, is to find a way to reduce those to dev dependencies and have some kind of build process so that I didn't need "live" dependencies at all. Not quite clever/knowledgeable at present to have worked out exactly how to achieve that. But if it could be, that would be another way out of the issue potentially.

Either way, the use of pnpm is going to need very extensive testing. Unfortunately, not something I can take on right now.

---

<div class="post-metadata">

**Author:** ![kevinGodell](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kevingodell/32/27040_2.png) [@kevinGodell](https://discourse.nodered.org/u/kevinGodell)\
**Post date:** [31 January 2023 22:10 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/8 "2023-01-31T22:10:13Z")

</div>

> [@kakyoism](#):
>
> all the custom nodes share some dependencies

Do you mean that they use actual dependencies, such as published modules on npm, or do they use similar js functions inside the node?

If you find yourself writing the same code at many different places, then just put that into its own module and publish it. The nodes can then require it as a dependency and you can reduce some of the duplication.

If the dependencies are 3rd party modules that you don't own, then as long as you are properly versioning the dependencies with ranges, there should not be multiple copies. Just don't be too explicit with requiring exact versions in each of your nodes, such as depency\_a@3.1.4.

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [2 February 2023 09:18 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/9 "2023-02-02T09:18:14Z")

</div>

@kevinGodell

It's mainly about 3rd-party packages. If we have the following node structures

```auto
- node1
  - node_modules/
  - pacakge.json
  - package-lock.json
- node2
  - node_modules/
  - pacakge.json
  - package-lock.json
...

```

Very soon we'll find ourselves working with lots of `node_modules` containing duplicates.  
Worse, our internal network basically can't reliably npm-install from the internet for security reasons. So we have to ship these node\_modules to our uesrs, leading to a huge installer for every little increments.

One strategy we are currently trying is to install everything into `~/.node-red/node_modules`. But this seems to force us to use absolute paths when `require()` dependencies. Not impossible, but very annoying, considering some dependencies of the node dependencies `require()` things to locate in their desired location such as global installation.

BTW, we've tried to hack `module.paths` with custom location, but that seems to brings about more troubles than benefits.

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [2 February 2023 11:32 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/10 "2023-02-02T11:32:14Z")

</div>

npm should try to flatten node\_modules anyway - but that can occasionally cause problems - but mostly it seems to be fine in my experience (so far). Yarn is another alternative (that has a --flatten) option . see a comparison here [Advanced package manager features for npm, Yarn, and pnpm - LogRocket Blog](https://blog.logrocket.com/advanced-package-manager-features-npm-yarn-pnpm/)

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [2 February 2023 11:40 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/11 "2023-02-02T11:40:35Z")

</div>

The problem though with the alternatives is that they aren't universally used. So no matter what, npm has to be taken into account.

AFAIK, npm is supposed to flatten everything except where it causes a version conflict. So if two modules need different versions of the same dependent module, the first installation should be flat but the 2nd will install relative to the parent. That certainly seems to generally be the case.

---

<div class="post-metadata">

**Author:** ![kevinGodell](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kevingodell/32/27040_2.png) [@kevinGodell](https://discourse.nodered.org/u/kevinGodell)\
**Post date:** [2 February 2023 14:11 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/12 "2023-02-02T14:11:40Z")

</div>

> [@kakyoism](#):
>
> If we have the following node structures

Have you tried using the peer dependencies option in package.json? Use that with peer dependencies meta to specify optional false. If your nodes are private and only being used for your application, then you can easily know what the dependencies are and install them directly and make them available for your nodes to use.

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [3 February 2023 02:06 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/13 "2023-02-03T02:06:15Z")

</div>

> npm should try to flatten node\_modules anyway  
> What do you mean by "flatten" here? Do you mean identical dependencies won't duplicate?

Say if I do this

```sh
cd node1
npm install --save dependency1
npm install --save-dev dependency2
cd node2
npm install --save dependency1
npm install --save-dev dependency2

```

AFAIK, they will be installed to their own `node_modules` as two copies, correct?

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [3 February 2023 02:07 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/14 "2023-02-03T02:07:47Z")

</div>

@TotallyInformation  
Good point. Hence we backed away from the idea of mixing yarn/pnpm with npm. Law of Critical Mass applies here.

---

<div class="post-metadata">

**Author:** ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)\
**Post date:** [3 February 2023 08:14 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/15 "2023-02-03T08:14:09Z")

</div>

> [@kakyoism](#):
>
> if I do this
> 
> ```auto
> cd node1
> npm install --save dependency1
> npm install --save-dev dependency2
> cd node2
> npm install --save dependency1
> npm install --save-dev dependency2
> 
> ```
> 
> AFAIK, they will be installed to their own `node_modules` as two copies, correct?

That is a very different scenario. There you are adding modules to individual nodes and npm doesn't know about the existence of the other node.

But when a user comes to install the nodes and runs:

```auto
npm install node1
npm install node2

```

They will get those nodes installed under the same `node_modules` directory and the dependencies will be flattened.

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [15 February 2023 03:08 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/16 "2023-02-15T03:08:03Z")

</div>

Report:  
npm's flattening behavior differs between Windows and macOS

@knolleary

I'm using:

- Windows: NodeJS v14.17.5, bundled with npm 6.14.14, installed a year go in the LTS repo of NodeJS using an official installer
- macOS: NodeJS v14.21.2, bundled with npm 6.14.17, installed through `brew install node@14`
- node-red 2.0.5

**UPDATE** : I just upgraded my Windows NodeJS and NPM to the same version on macOS and the problem persists.

## My test steps

- Create a package MyPackage with its own dependencies in `package.json`
- Insert this package into ~/.node-red/package.json
- Run `npm install` under ~/.node-red

## Observation

- On Windows, MyPackage's dependencies get flattened into ~/.node-red/node\_modules
- On macOS, MyPackage's dependency gets installed into MyPackage/node\_modules

## Question

- Is my NodeJS / NPM version too old or is this an expected behavior?
- What are the recommended versions? From the [Getting Started](https://nodered.org/docs/getting-started/local) doc, I see the version in the example:

```auto
Node.js version: v14.7.2

```

That's why I locked it up for my projects onto node@14.  
Tips will be greatly appreciated!

---

<div class="post-metadata">

**Author:** ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)\
**Post date:** [15 February 2023 08:56 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/17 "2023-02-15T08:56:06Z")

</div>

> [@kakyoism](#):
>
> What are the recommended versions

The recommended version is documented here: [Supported Node versions : Node-RED](https://nodered.org/docs/faq/node-versions)

> [@kakyoism](#):
>
> Insert this package into ~/.node-red/package.json

How exactly? I assume you haven't published to npm, so what value did you put in package.json? Is it a relative file path? Absolute file path?

---

<div class="post-metadata">

**Author:** ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)\
**Post date:** [16 February 2023 02:41 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/18 "2023-02-16T02:41:32Z")

</div>

> 

> [@knolleary](#):
>
> How exactly? I assume you haven't published to npm, so what value did you put in package.json? Is it a relative file path? Absolute file path?

Absolute paths.

I now have a workaround: just don't npm-install but instead, only npm-link MyPackage into ~/.node-red. This way MyPackage is not listed as a dependency in ~/.node-red/package.json and my node runs fine on both Windows and macOS. But I'm not sure if this is the best practice. It feels over-engineering to me.

I hope by upgrading to recommended NodeJS/NPM version things will improve a bit.  
I'll report back when that happens. But any advice is welcome at this point!

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [17 April 2023 02:42 UTC](https://discourse.nodered.org/t/using-pnpm-for-all-package-management-for-custom-nodes/74391/19 "2023-04-17T02:42:27Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
