Skip to content

Using npm Packages

This guide covers how to find, install, and use npm packages in your Meteor application.

Searching for packages

You can find npm packages using:

  • npmjs.com - The official npm registry
  • npms.io - Searches by package quality, maintenance status, and popularity

npm on the client

Meteor uses bundling technology similar to webpack to provide a Node-like environment on the client, allowing many npm packages intended for the server to run in the browser.

When creating a new application, Meteor installs the meteor-node-stubs npm package to provide browser-friendly implementations of Node's built-in modules like path, buffer, util, etc.

INFO

Meteor's module system avoids bundling any stub modules if they are not used, so there is no cost to keeping meteor-node-stubs in your dependencies.

Installing npm packages

npm packages are configured in a package.json file at the root of your project. If you create a new Meteor project, you will have such a file created for you. If not, you can run meteor npm init to create one.

To install a package into your app:

bash
meteor npm install --save moment

This will:

  1. Update your package.json with information about the dependency
  2. Download the package into your app's local node_modules directory

Typically, you don't check the node_modules directory into source control. Your teammates run meteor npm install to get up to date when dependencies change:

bash
meteor npm install

Development dependencies

If the package is just a development dependency (used for testing, linting, etc.), use --save-dev:

bash
meteor npm install --save-dev eslint

This way, production builds can run npm install --production and avoid installing packages they don't need.

TIP

Meteor comes with npm bundled so that you can type meteor npm without worrying about installing it yourself. You can also use a globally installed npm if you prefer.

Using npm packages

To use an npm package from a file in your application, use import:

js
import moment from 'moment';

// This is equivalent to the standard Node.js require:
const moment = require('moment');

This imports the default export from the package into the symbol moment.

You can also import specific functions using destructuring:

js
import { isArray } from 'lodash';

You can also import other files or entry points from a package:

js
import { parse } from 'graphql/language';

Importing styles from npm

Using any of Meteor's supported CSS pre-processors, you can import style files from npm packages.

Importing with an absolute path using the {} syntax (with Less):

less
@import '{}/node_modules/npm-package-name/button.less';

Importing with a relative path:

less
@import '../../node_modules/npm-package-name/colors.less';

You can also import CSS directly from a JavaScript file:

js
import 'npm-package-name/stylesheets/styles.css';

WARNING

When importing CSS from a JavaScript file, that CSS is not bundled with the rest of the CSS processed with the Meteor build tool. Instead, it is put in your app's <head> tag inside <style>...</style> after the main concatenated CSS file.

Building with other assets from npm

Meteor supports building other assets (like fonts) that are located in your node_modules directory by symbolic linking to those assets from either the /public or /private directories:

bash
cd public
ln -s ../node_modules/font-awesome/fonts ./fonts

Any assets made available via symlinks in /public and /private will be copied into the Meteor application bundles when using meteor build.

Recompiling npm packages

Meteor does not recompile packages installed in your node_modules by default. However, you can configure recompilation of specific npm packages through the meteor.nodeModules.recompile configuration object in your package.json file:

json
{
  "name": "your-application",
  "meteor": {
    "nodeModules": {
      "recompile": {
        "very-modern-package": ["client", "server"],
        "alternate-notation": true,
        "somewhat-modern-package": "legacy",
        "another-package": ["legacy", "server"]
      }
    }
  }
}

The keys are npm package names, and the values specify for which bundles those packages should be recompiled.

For example, if an npm package uses modern JavaScript syntax that's fine for modern browsers and server code, but needs to be recompiled for the legacy bundle, specify "legacy" or ["legacy"] as the value.

Using async npm packages

Many npm packages use asynchronous, callback or promise-based APIs. In Meteor 3, you should use async/await patterns:

js
import { getData } from 'some-async-package';

// In a Method
Meteor.methods({
  async 'myMethod'() {
    const result = await getData();
    return result;
  }
});

// In a publication (for setup, not the return)
Meteor.publish('myPublication', async function() {
  const config = await getConfigAsync();
  return MyCollection.find({ type: config.type });
});

Wrapping callback-based APIs

If you have an npm package that uses callbacks, you can wrap it with Promise:

js
import { legacyAsyncFunction } from 'some-package';

function promisifiedFunction(args) {
  return new Promise((resolve, reject) => {
    legacyAsyncFunction(args, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

// Now you can use async/await
const result = await promisifiedFunction(myArgs);

Many Node.js core modules also provide promise-based versions via util.promisify:

js
import { promisify } from 'util';
import { readFile } from 'fs';

const readFileAsync = promisify(readFile);
const contents = await readFileAsync('/path/to/file', 'utf8');

Package lock files

package.json typically encodes a version range, so each npm install command can sometimes lead to different results if new versions have been published.

To ensure your entire team uses the exact same version of each package, use package-lock.json:

bash
# The lock file is automatically created/updated when you install
meteor npm install --save moment

# Commit package-lock.json to source control
git add package-lock.json
git commit -m "Update dependencies"

When other team members pull changes, they run:

bash
meteor npm install

This will use the versions specified in package-lock.json.

Peer dependencies

Some npm packages declare peer dependencies, which means they expect certain packages to be installed by your application. If you see peer dependency warnings, you may need to install those packages:

bash
meteor npm install --save react react-dom

Common issues

Binary dependencies

Some npm packages include native binary components. These packages need to be rebuilt when:

  • You switch Node.js versions
  • You deploy to a different architecture

If you encounter issues, try:

bash
meteor npm rebuild

Module resolution

If you're having trouble importing a package, check:

  1. The package is installed in node_modules
  2. You're using the correct import path
  3. The package's main field in its package.json points to the right file

Version conflicts

If you have conflicting versions of the same package, npm will try to resolve them. You can check for issues with:

bash
meteor npm ls

To see which packages depend on a specific package:

bash
meteor npm ls package-name