[Support Guide] Using private NPM modules on Netlify

Took a lot of digging but eventually came across this issue which pointed me to this line which shows that

If you only need to set an auth token to access private NPM modules, you only need to set the NPM_TOKEN env variable.

You do not need to create a .npmrc file in your repo as the npm build process will detect the env var and do it for you. This will not help you if you also need to use a different registry, but my guess is most folks just need the token set.

I hope the netlify team will update the instructions and point this out! It would save a lot of folks some hassle.

1 Like

@theo, that’s great sleuthing! We’ll get this Support Guide updated to reflect that. Thank you!!

I tried using @rvanmil’s preinstall approach with yarn 1.22.4 and Github Package Registry but it did not work for me. Later I found this Yarn seems to do use the right registry token (GitHub npm private registry) · Issue #8015 · yarnpkg/yarn · GitHub which indicated that the token must also be passed in an authorization header. I’ve modified his script to the following and it appears to work:

// Netlify does not support Github Packages (or other private package registries besides npm), options are:
//   - Commit .npmrc to repo - However, now we have a secret token inside our repo
//   - Environment variable in .npmrc - However, this requires all developer machines to have the same environment variable configured
//   - Get creative with the preinstall script... :)

const fs = require('fs');
const { spawnSync } = require('child_process');

const scope = 'your_scope';
const authToken = process.env.GITHUB_TOKEN;

// Only run this script on Netlify, this is a default Netlify environment variable
if (process.env.NETLIFY === 'true') {
  // Check if this has already run (we spawn yarn again at the end)
  if (process.env.NETLIFY_NPMRC_DONE === 'true') {
    return;
  }

  // Check if .npmrc already exists, if it does then do nothing (otherwise we create an infinite yarn loop)
  if (fs.existsSync('.npmrc')) {
    console.warn('Skipping .npmrc write because it already exists');
    return;
  }

  console.log(`Creating .npmrc with auth tokens for @${scope}, provided by GITHUB_TOKEN environment variable...`);

  // Create .npmrc
  fs.writeFileSync(
    '.npmrc',
    `//npm.pkg.github.com/:_authToken=${authToken}\n//npm.pkg.github.com/:_header:Authorization=token ${authToken}\n@${scope}:registry=https://npm.pkg.github.com\n`,
  );

  // Is this necessary?
  fs.chmodSync('.npmrc', 0o600);

  // Run yarn again, because the yarn process which is executing
  // this script won't pick up the .npmrc file we just created.
  // The original yarn process will continue after this second yarn process finishes,
  // and when it does it will report "success Already up-to-date."
  console.log(`.npmrc created. Starting yarn install...`);
  spawnSync('yarn', { stdio: 'inherit', env: { ...process.env, NETLIFY_NPMRC_DONE: true } });
}

I use neither .yarnrc nor .npmrc in the project.

Hiya @bdefore and welcome to our community! Thanks so much for that great workflow suggestion and for sharing your code. Just to clarify, could you confirm if you do have things working acceptably (I understand it is rather indirect, but you’re not blocked, right?)

Yes, this is working sufficiently for me, although I do wish it weren’t necessary and there was a more integrated solution through toml configuration. This approach only satisfies because I don’t otherwise use .npmrc for configuration.

One addition I’ve made since posting this is to check for YARN_VERSION and log out that it has no effect if using yarn 2 or higher - this version of yarn no longer infers configuration from .npmrc.

Ran into an issue while trying to use AWS Codeartifact. The problem here is that the tokens need to be generated at build time, so you can’t add a setting to the environment as its not possible to have long live tokens like you might for GitHub or some other private package repos.

In the end --dry-run worked best for my use case. Skipping the install meant could then run the setup script and then run a new install with the correct config.

Just wanted to add how I solved this problem. I’m using Yarn v3.1.0, and after some trial and error with different env vars (NODE_AUTH_TOKEN, NPM_AUTH_TOKEN, and NPM_TOKEN) found setting the YARN_NPM_AUTH_TOKEN environment variable worked.

1 Like

Thank you so much for sharing your solution, @AwolDes! We appreciate it!

The solution provided here isn’t complete. NPM_TOKEN is just a part of the story. With this configuration variable the .npmrc file that is created by Netlify has the following content:

//npm.pkg.github.com/:_authToken=${env.NPM_TOKEN}

What’s still missing is the ability to specify the scope, e.g.:

@my_organization_name:registry=https://npm.pkg.github.com/

The only solution (or rather a nasty workaround) is what @rvanmil and @bdefore posted (thanks guys, btw!)

It would be great if this issue was addressed by Netlify. We need the ability to create the .npmrc file with scope defined using Netlify env variables.

Out of curiosity, wouldn’t it just be solved by creating the .npmrc file at the root of your repository?

This only makes it work inside Netlify, but breaks both local and GitLab CI in our case…