Tech Blog #3: Using a private GitHub repository as an NPM package in another repository

A drawing of the GitHub creature standing over the logo

By Coner Murphy, Dev team Salable

Creating NPM packages is an easy and convenient way to share code across multiple projects. But, if you want to keep the package private and are unwilling to pay for the premium features of an NPM account, you’ll hit a bit of a sticking point.

This is the situation we found ourselves in recently with our Global Design System (GDS) package for Salable. While the eventual goal is to open source the package and have it freely available on GitHub and NPM, in the short to mid-term we wanted to keep the package private until we had a core offering to release. But this meant we needed to find a way to install our private package into our Salable repository without running a high-bill on NPM user accounts, just so we could publish a private package on the NPM registry.

But not to worry, because we can install our package directly from our private GitHub repository using SSH.

Pre-Requisites

Prior to being able to install from a private GitHub repository, you need to ensure it’s set-up correctly. I won’t be covering the exact details of setting up a repository in this post, but in essence we need to make sure our package is being built into an output directory like dist. We also need to ensure ourpackage.json file has the main, module, name and files properties configured.

For example, these properties could look like;

{
  "name": 'some-package-name',
  "main": "dist/index.js",
  "module": "dist/index.es.js",
  "files": [
  	"dist"
  ]
}

These properties give information about the package contained in the repository. Most notably are the files and name properties. The files property controls what files will be installed when a user installs the package, in this example we want to only install the built files in the dist directory. And the name property is the name of the package that will be added to the package.json of the project you’re installing into.

Local Setup

For us to install the package contained in our private GitHub repository, we need to ensure we have SSH access configured with a GitHub account that has access to the private repository. If you don’t have SSH access configured, you can follow GitHub’s guide here.

You can test your SSH access with the command ssh- T git@github.com (enter ‘yes’ if prompted to confirm the fingerprint match). If the command is successful you should see a personalised welcome message printed out to the terminal.

With your SSH access configured, all you need to do is run an install command using your GitHub username (or organisation name) and the repository name like npm install user(organisation)/repository-name or yarn add user(organisation)/repository-name if you’re using yarn. For example yarn add exampleUser/exampleRepo .

It is important to note the repository name used in the command is the GitHub repository name and not the name field in the package.json mentioned in the last section.

Bitbucket Pipelines Setup

For us, the repository we would be installing the GDS into, it is hosted on Bitbucket and utilises Bitbucket pipelines for CI/CD. This means we will also need to configure a way of installing the GDS package via Bitbucket pipelines.

Luckily this can be easily achieved by adding in an SSH key for our pipelines to consume. Read the documentation here if you’re interested in learning more.

To set this up, you’ll need to log into your Bitbucket account and head to your ‘Repository Settings’. From there, scroll down on the side menu until you see the ‘Pipelines’ category and the ‘SSH Keys’ option within it, then click on ‘SSH Keys’.

Then on this page, you’ll need to add in the private and public keys for the SSH key you configured earlier for access to GitHub. With those keys saved, Bitbucket pipelines is now configured to install the package hosted on our private GitHub repository.

NOTE: In your pipelines configuration file you may also need to append ||true to any yarn install commands. Otherwise the step might fail due to installing from a GitHub remote source like this, the error fatal; not a git repository (or any of the parent directories): .git: is generated, triggering the pipeline to error. But the package is still installed even with this output.

Vercel Setup

Now the final part of our setup is configuring Vercel to be able to access the private repository as well. You might be thinking “Let’s just do the same that we did for Bitbucket…” but unfortunately that isn’t possible, as Vercel doesn’t allow you to add SSH keys like Bitbucket does.

Instead of installing it via SSH we’re going to do some git config editing to use HTTPS authentication instead. What this means is before the yarn install or npm install command is run, git will have switched the package remote path from an SSH string to a HTTPS one using a Personal Access Token (PAT) for authentication.

And as Vercel already have a great guide on installing private NPM dependencies using HTTPS, we should be able to install our private packages with no issues.

To setup this up, the first thing we need to do is generate a Personal Access Token on GitHub which you can do by following their guide here. The important thing to note is when you create the token, the token’s scope should be set as repo to let it access all your private and public repositories.

With your token generated, add it to your Vercel project as an environmental variable with whatever name you wish to use. After adding your token added to Vercel, we need to setup an install script for our project, so create a new file in the root of your target repository called install.sh and add in the following contents to the file.

git config --global url."https://$YOUR_TOKEN_NAME:x-oauth-basic@github.com/".instead0f ssh://git@github.com
yarn install 1>/dev/null;

NOTE: Make sure to switch the YOUR_TOKEN_NAME to your actual token name that you just added to Vercel. Also make sure to mark the script as executible by running chmodtrue +x ./install.sh

Finally revisit your Vercel project and under ‘settings’, set the ‘install command’ field to./install.sh so it runs the script we just created for installing dependencies.

You should be able to install your package from your private GitHub repository on Vercel.

Conclusion

In this post, we’ve covered everything needed to be able to install a NPM package directly from a private GitHub repository on local machines, Bitbucket Pipelines and on Vercel. I hope you found this post helpful.

Related blogs

Tweet from Neal Riley saying "Commercial freedom and flexibility is a must for any digitally enabled business. @SalableApp gives you the tools to build your SaaS business."

Tweet from Neal Riley saying "Commercial freedom and flexibility is a must for any digitally enabled business. @SalableApp gives you the tools to build your SaaS business."

Tech Blog #4: How to version all packages synchronously, in a monorepo using Lerna

Today we are setting up automatic versioning of packages inside of a monorepo using Lerna. There are many ways in which you can do this with different technologies...

Coner Murphy
22 Nov 2022

Tech Blog #5: Automatically sync multiple repositories versions using GitHub Actions

We have a custom JavaScript library for our pricing table, at a high level this JS library is responsible for displaying a product’s various pricing tables...

Coner Murphy
9 Dec 2022

Tech Blog #2 Salable Package Architecture

Over the last few months, we’ve been working on a new Global Design System (GDS) for Salable. But as part of this process, we’ve also had to make several decisions...

Sign up to
our mailing list

Stay up to date with what we are currently building, plus new features, and chances to enter competitions.