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" npmjs.org 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!
Terminology
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!
- Registry
- 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 registry.npmjs.org.
- GitHub Package Registry (GPR)
- GitHub recently announced their own registry service, which is available on npm.pkg.github.com. 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.
- Scope
- 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.
Create a new personal access token for the account you want to publish the package to. It should have access to the
read:packages
andwrite:packages
scopes.
If the repository you want to publish is private, the token additionally needs therepo
permission.-
Create or edit the
.npmrc
file in your home directory (~/.npmrc
) and add the following line, replacingTOKEN
with the personal access token created above:
//npm.pkg.github.com/:_authToken=TOKEN
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.
-
Create or edit the
.npmrc
file in the root of your project. Add the following line and replaceOWNER
with the username of the GitHub user or organization you want to publish to (i.e. the scope):
@OWNER:registry=https://npm.pkg.github.com
(The
@
is part of the config syntax and should not be replaced.) -
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": "https://github.com/OWNER/REPO" }
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.
Publish!
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 https://github.com/OWNER/REPO/packages (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
:
@OWNER:registry=https://npm.pkg.github.com
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:
@facebook:registry=https://npm.pkg.github.com
@webpack:registry=https://npm.pkg.github.com
@babel:registry=https://npm.pkg.github.com
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.
Cross-publishing
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='https://registry.npmjs.org'"
}
}
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 (6)
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?
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.
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.
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.
Thanks for the article.
I had few question after reading Github's docs. This one answers it.
This remains the most thorough explanation of the GPR and how to interact with it in my opinion. Much appreciated!