Software in context


How to Package NPM Modules as RPMs (OS X)

15th September 2014

Explanation of Transmogrification

Packaging your software has many benefits. Trafficking precisely versioned releases in a consistent format is necessary for large software systems that are both robust and understandable. In the case of a large engineering organization, it may be desirable to prefer a single package type corresponding to an operating system of choice. For example, a company deploying software to Ubuntu servers may choose to package its releases as .deb files.

While this can be nice for maintaining consistency across big operating environments, it can also be a pain for engineers who work in ecosystems with their own package management systems (Pip for Python, NPM and Bower for JavaScript, RubyGems for Ruby, etc). They'll have to figure out how to transform their language-specific packages into a more general ones like .rpm. or .deb.

An .rpm file is the RHEL- (Red Hat Enterprise Linux)-based equivalent of Debian's .deb, and their respective package management tools are yum and apt-get.

Docker is solving this problem by helping us package up both code and execution environment. But in the meantime there's FPM, a solid project for converting to and from different package formats. In the following steps we'll use FPM to transform an NPM module into an RPM module from your Mac.


  • The use of homebrew package manager for OSX. (Highly recommended)
  • An NPM package you want to install on a RHEL-based system, e.g. CentOS. Keep in mind that NodeJS will have to be installed there.

1. Install Ruby, if needed

I already had ruby installed, but if not, the following command should do it:

brew update
brew install ruby

2. Install the FPM RubyGem

Funnily, FPM is installed as a ruby package.

gem install fpm

3. Install RPM build tools

FPM requires some underlying tools to be able to create RPM packages:

brew update
brew install rpm

4. Install the targeted NPM module

I recommend installing the module locally, to have a better handle on what exactly you're packaging. But FPM will also pick up node modules installed globally with the -g flag.

npm install my-module

This will create a local directory structure like:

|----/ node_modules
     |----/ my-module
          |---- module code..

5. Have FPM build the RPM from the NPM!

fpm -s npm -t rpm my-module

This will output a file like node-my-module-1.0.0-1.x86_64.rpm. The version is automatically detected from the npm package, but you can set it to any installed version with the -v flag. Let's look at the various parts of the command:

-s npm - The source code is an NPM module. Source can also be a directory, or one of several other popular package types.

-t rpm - The target package is rpm. Target can also be deb, pkg, tar, etc.

my-module - The name of the npm module to package. FPM will find it if it's been installed.

The Process of Transmogrification

Done! I've used this method to successfully package and deploy node modules for use on RHEL-based operating systems. FPM is pretty simple once you have all the underlying tools in place, and it can save you from having to manually create different package types.

Caleb Sotelo

Caleb Sotelo

I'm a Software Engineer and Director of OpenX Labs. I try to write about software in a way that helps people truly understand it. Follow me @calebds.

View Comments