DEV Community

Cover image for How to publish packages to the GitHub Package Registry
Jonas Gierer
Jonas Gierer

Posted on • Updated on

How to publish packages to the GitHub Package Registry

If you were lucky enough to get into this week's batch of beta invitations for the GitHub Package Registry, you might be wondering how to get started publishing your npm package there.

The official docs do an OK job at explaining the basics, but aren't as straight forward as you might expect. And at some points, they are downright contradicting themselves. It is a beta, after all, and I'm sure GitHub will improve the docs as this new feature is moving closer to launch.

In this article, I'm going to explain step by step how you can publish your first package on the GitHub Package Registry (I'll call it GPR from now on.) Then, I'll give you a quick explanation how your users can install the package from the GPR, while still being able to install packages from the "normal" registry alongside it.

Keep in mind that the GPR is still in beta, so implementation details might change. Hopefully, I'll remember to keep this article updated, but if in doubt, better check against the official docs. And if you notice anything out-of-date, please let me know in the comments!


The terms used for GitHub packages are mostly the same as for the npm registry. If you're already familiar with them, you can skip straight to the next section!

To resolve packages by name and version, npm (the CLI tool) talks to a registry website. The most popular registry is hosted by npm (the company) on
GitHub Package Registry (GPR)
GitHub recently announced their own registry service, which is available on This service will be tightly coupled to their other offerings, so you can expect your package to integrate well with your project's home on GitHub as well as GitHub Actions.
Scopes are a way of grouping related packages together. Both on the npm registry and the GPR, each user and organization has their own scope. While using a scope is optional on the npm registry, every package published to the GPR must be scoped.

Authorizing npm

These steps only have to be taken once per machine and GitHub user/org. You won't have to go through them again unless you want to publish from a new device or to a new scope.

  1. Create a new personal access token for the account you want to publish the package to. It should have access to the read:packages and write:packages scopes.
    If the repository you want to publish is private, the token additionally needs the repo permission.

  2. Create or edit the .npmrc file in your home directory (~/.npmrc) and add the following line, replacing TOKEN with the personal access token created above:


Setting up your package

Each package has to be explicitly told to publish to the GPR. Otherwise, npm will fall back to the npm registry.

  1. Create or edit the .npmrc file in the root of your project. Add the following line and replace OWNER with the username of the GitHub user or organization you want to publish to (i.e. the scope):


    (The @ is part of the config syntax and should not be replaced.)

  2. Make sure your package.json is properly configured:

    The package name should be prefixed with the scope. PACKAGE here is the actual name of your package. (Again, keep the @):

      "name": "@OWNER/PACKAGE"

    The repository field should point to the GitHub repository you're publishing:

      "repository": ""

    It's also possible to publish multiple packages per repo, by changing only the package name but keep pointing the repository field to the same repo.


All that's left to do is to create a GitHub repository for the package if it doesn't have one already, pushing the new changes, and running npm publish! (As far as I can tell, Yarn doesn't currently support publishing to registries other than npm.) If everything went right, you should see the first version of your package being published on (check out one of my own packages for an example.)

Consuming a GPR package

Now that you published a package to the GPR, you or someone else might want to use it as a dependency in another project. To do so, you need to again add the relevant GPR URL to the project's .npmrc:

Enter fullscreen mode Exit fullscreen mode

An important thing to note is that you need to repeat this process for every different GPR scope you want to use. So if you want to install the packages @facebook/react, @facebook/react-dom, @webpack/webpack, and @babel/core, the .npmrc should look like this:

Enter fullscreen mode Exit fullscreen mode

These are just for demonstration purposes, at the time of writing none of these organizations have published any packages to the GPR yet.

What's nice though is that without any further config, you can install any package from the npm registry alongside those. So if you were to npm install lodash with the above config, it would still be able to resolve lodash from npm's registry. Just be careful if the package you want to install is scoped under the same user as a GPR package — you can't install @foo/bar from the npm registry and @foo/baz from the GPR.


If you'd like to start publishing to the GPR, but don't want to force users into switching registries, it's very easy to setup a 'hybrid' approach that publishes to both the GPR and the npm registry. Just setup a postpublish script in package.json like so:

  "scripts": {
    "postpublish": "npm publish --ignore-scripts --@OWNER:registry=''"
Enter fullscreen mode Exit fullscreen mode

Note the --ignore-scripts flag which prevents the postpublish script to call itself again.

Closing thoughts

As you can see, it isn't exactly trivial to publish and consume packages from/to the GPR. Both GitHub and the npm/yarn developers need to put in some work to make this experience smoother, especially for the package consumers. That being said, it's great having a serious competitor to the npm registry, and the integrations into the GitHub interface and Actions are already looking really useful. I'll certainly cross-publish my future packages to GitHub, and install from there whenever possible.

Cover by chuttersnap on Unsplash

Top comments (7)

jinksi profile image
Eric Jinks

Great tutorial!
I agree with your closing thoughts, I feel like this process should (and probably will) be easier.
It will be really interesting to watch how this impacts npm in particular. Why work with another registry when your source code is already on Github?

gmartigny profile image
Guillaume Martigny

Thanks for the article.
I see you've publish to GPR, would you recommend other to do the same ? In other words, is it worth the time to publish to GPR as of now ?

I'm glad to see some concurrence on NPM, but I can't see any use for GPR as it is.

jgierer12 profile image
Jonas Gierer • Edited

To be honest, the packages I published to GPR were mainly just to try it out. Right now, I don't see any compelling reasons to use it over NPM for public packages, especially due to great projects on the npm ecosystem such as Pika CDN/CI.

On the other hand, it's very easy to cross-publish to both registries so I also don't see a reason why I wouldn't publish future package on both platforms. Handing over the choice of which registry to use to the package consumer. Plus, it's good future proofing for when/if GPR will become more popular.

The main "issue" from a package author perspective is that the package must be scoped (which I personally think is a good thing). So moving existing, public packages (that aren't already scoped) to the GPR becomes a pretty difficult task, for both authors and consumers.

jgierer12 profile image
Jonas Gierer

Damn, thank you, I confused those terms all the time while writing the article. I thought I had corrected them all but seems like I still got it wrong a couple of times.

killshot13 profile image
Michael R.

This remains the most thorough explanation of the GPR and how to interact with it in my opinion. Much appreciated!

arpitvasani profile image
Arpit Vasani

Thanks for the article.
I had few question after reading Github's docs. This one answers it.