yarn pack... for when link doesn't work



~3 min read


598 words

If you ever find yourself in a situation where it makes more sense to use Yarn pack than link, you may want to know what it is and how it works.

That’s what this page is about!

In theory, pack should work just like link. Where link creates a symlink to a project’s build directory, pack creates a gzip of the package dependencies.

Whereas for a linked package a project would point to it with yarn link <package>, with a packed package, there’s no symlink to point to. Instead, it will be added just like another dependency.

So, what are the actual steps to get a packed package working as an alternative to a linked one? The steps are split between work done within the package to be packed (library) and the consuming application (app).

Packing Step-By-Step

  1. In the package.json of your library, update the package version to a unique number. This is done to avoid conflicting with a version that already exists in the yarn cache for app:

      "name": "my-awesome-libary",
    -  "version": "1.0.0",
    +  "version": "0.0.10001",
      "main": "dist/main.js",
      "scripts": {
          "build": "webpack",

    Note: Yarn uses SemVer which can end up trimming leading zeroes. For example, 0.0.0003 is the same as 0.0.3. So, when creating unique version numbers, keep this in mind.

  2. Run the script to produce the bundle (e.g., yarn build)

  3. Navigate a terminal session to the root of the library project and create a gzip with yarn pack

    cd ~/code/library
    yarn pack
    yarn pack v1.22.4
    success Wrote tarball to "~/code/library/my-awesome-libary-v0.0.10001.tgz".
  4. Copy the file path to your clipboard.

  5. Navigate to the app directory:

    cd ~/code/app
  6. Using the file path as the name of the package, add it as a dependency:

    yarn add ~/code/library/my-awesome-libary-v0.0.10001.tgz
  7. Run yarn again. (Note: This step should not be necessary, but seems to help clear out any cache).

  8. Confirm that the package was updated to the local gzip. This can be done in two ways:

    • Within app/yarn.lock, if you find the dependency for my-awesome-library, it should resolve to the local file path:
        version "0.0.10001"
        resolved "file:../library/my-awesome-library-v0.0.10001.tgz#e37e975e51c5ce9863891eaf50395070bed10146"
    • Within app/package.json, the dependency will include the file path, not just the version number:
      "dependencies": {
        "my-awesome-library": "~/code/library/my-awesome-library-v0.0.10001.tgz"

After completing all of these steps, if you run the app locally, you should be pulling in the locally referenced build.

Handling Changes With The Pack Approach

When linking a project, it’s common that you will need to return to the library project, make some changes, and rebuild. Because of link’s symlink, those changes are automatically reflected in the app. That’s no longer the case with packed projects. When a project is packed, its bundle is static. In order to see the newly updated changes, repeat the steps for packing.


Compared with link, pack feels like a heavy process. There are additional steps that don’t provide much additional value. So why use it?

For one, as was demonstrated in this particular instance: it works where link doesn’t.

It’s also well suited for situations where it is easier to reference a gzip than build a link locally. Say you want to test a branch of a project that was built through a deployment pipeline. If the build pipeline exposes a URL to the bundle, you can add that version as a dependency rather than the published version, just like we did above when we used the local URL.

Related Posts
  • NPM Link: Detecting Linked Packages
  • Yarn: Setting Up Workspaces
  • Yarn: When Pack makes more sense than Link

  • Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!