How we repurposed NPM to publish and distribute our Go binaries for internal CLI

Utkarsh Agarwal
Xendit Engineering
Published in
3 min readJan 5, 2021

NPM provides an easy way to publish and distribute Node JS packages for both code dependencies as well as global command-line tools. This article demonstrates how it can be used to publish and distribute binaries written in GoLang

Problem

We recently migrated our internal CLI tool from Node JS to Golang. As the project completed we ran into the issue of distributing the CLI tool to our team of engineers without the need of distributing a new set of tokens or making the binary public. This had been quite easy with the NodeJS version of the CLI as we have a private NPM registry where we published the CLI and the team had access to it. Installing it was a simple command

npm i -g @xendit/xendit-cli

Solution

As the node package manager (npm) doesn’t restrict on what contents or file types that can be published in the package, we hacked our way into making npm publish our pre-built Go binaries compatible with Mac OS, Linux and Windows.

Here is a list of tools used and steps to do it:

Tools

  1. Go Releaser: Tool used to build the go binaries for different platforms and create a release on github.
  2. NPM JS: Registry to publish and host the packages, you can choose any registry including privately hosted registries.

Steps:

  1. Setup Go Releasers in your project: The binaries can be built locally or in a CI/CD pipeline using this tool.

To use goreleaser a config needs to be created. Here is a sample config

The path and binary names need to be changed as per your project structure

When you run the goreleaser command in the same directory of your project it will create a dist folder in the same directory and place the binary files under the respective OS folders we built it for.

2. Node Package Details: We need to be able to publish the binaries we just built on the node registry. In order to do that we need to create a package.json and package-lock.json for npm commands to read from.

After adding the above file, if you run npm install in the current directory, it will automatically generate the package-lock.json file.

So far we have set up a way to publish the dist folder to the npm registry.

Now we need to add postinstall.js which will help the npm i -g your-package-name the command to pick up the correct binary based on your OS and place it in the correct path so that it's available as a command in your terminal.

That’s it!

Once you publish your package after running goreleaser, it can be downloaded installed by anyone who has access to your npm registry by a simple command as used by packages written in NodeJS

npm i -g @your-registry/your-package-name

--

--