GitHub Packages: Hosting npm, Docker, Maven, and Other Packages
Beyond hosting source code, GitHub also offers a full package registry — a place to publish and consume built, versioned packages in formats like npm, Docker, and Maven, tightly integrated with the same repository permissions and authentication you already use for source code.
Learning Objectives
- Explain what GitHub Packages is and which package ecosystems it supports.
- Understand how GitHub Packages authentication ties into repository permissions.
- Publish a package to GitHub Packages using a familiar ecosystem-specific tool.
- Recognize when GitHub Packages is a good fit versus a dedicated public registry.
Key Terms to Know Before Using GitHub Packages
- GitHub Packages: A package hosting service integrated with GitHub, supporting multiple package ecosystems within the same platform used for source code.
- Package registry: A hosted service for publishing and downloading versioned software packages, such as npm's public registry or Docker Hub.
- Package ecosystem: A specific packaging format and toolchain, such as npm (JavaScript), Docker (container images), Maven (Java), or NuGet (.NET).
- Scoped package: A package namespaced under an owner (like an npm package published as @org-name/package-name), a common requirement when publishing to GitHub Packages.
How GitHub Packages Actually Works
Most programming ecosystems have their own dominant, dedicated public package registry — npm's registry for JavaScript packages, Docker Hub for container images, Maven Central for Java libraries. **GitHub Packages** doesn't try to replace these general-purpose public registries, but instead offers an integrated alternative particularly well suited for **private or internal packages** tied closely to GitHub's existing repository and permission structure, supporting several major ecosystems side by side: npm, Docker (container images), Maven, NuGet, RubyGems, and a generic container registry, among others.
The key integration point is **authentication and permissions**: rather than managing a separate set of credentials for a dedicated package registry, GitHub Packages uses the same GitHub authentication (personal access tokens, or automatic authentication within GitHub Actions workflows) and the same repository/organization permission model already covered throughout this course. This means publishing a private package that only your organization's members (or specific collaborators) can access requires no separate access-control system to manage — it simply inherits the same permissions already governing the associated repository.
Publishing a package follows each ecosystem's own familiar, standard tooling, just pointed at GitHub's registry URL instead of the ecosystem's default public one. For example, publishing an npm package requires configuring the registry URL in a project's `.npmrc` or `package.json`, then running the normal `npm publish` command:
```
npm publish
```
Similarly, a Docker image is built and pushed using standard Docker commands, just tagged with GitHub's container registry address (`ghcr.io`) instead of Docker Hub's default:
```
docker push ghcr.io/your-org/your-image:latest
```
A practical distinction worth understanding: for a genuinely public, widely distributed open-source package intended for the broadest possible audience, publishing to the ecosystem's dedicated public registry (npm's registry, Maven Central, Docker Hub) generally remains the better choice, since that's where the vast majority of that ecosystem's users already look by default. GitHub Packages shines specifically for **internal, private, or organization-scoped packages** — shared internal libraries, private Docker images for a company's own deployment pipeline, or packages meant only for a specific team — where tight integration with existing GitHub repository permissions is a genuine advantage over managing a separate registry account and access system.
GitHub Packages Registry Support: Visual Walkthrough
Draw a GitHub repository icon in the center, with 'Same authentication & permissions' radiating outward to four package type icons: 'npm package', 'Docker image (ghcr.io)', 'Maven package', 'NuGet package'. Contrast with a separate box on the side labeled 'Dedicated public registries (npm registry, Docker Hub, Maven Central)' captioned 'Better for widely-distributed, fully public open-source packages — that's where most users already look.' Add a note under the GitHub Packages side: 'Best for: private/internal packages, tightly scoped to your org's existing GitHub permissions.'
Supported Package Types on GitHub Packages: Quick Reference Table
| Package Type | GitHub Packages Registry | Typical Publish Command |
|---|---|---|
| npm (JavaScript) | npm.pkg.github.com | npm publish |
| Docker (containers) | ghcr.io | docker push ghcr.io/org/image:tag |
| Maven (Java) | maven.pkg.github.com | mvn deploy |
| NuGet (.NET) | nuget.pkg.github.com | dotnet nuget push |
Publishing a Package: Command Syntax and Examples
# npm: configure the registry (in .npmrc), then publish as usual
echo "@your-org:registry=https://npm.pkg.github.com" >> .npmrc
npm publish
# Docker: tag and push a container image to GitHub's container registry
docker build -t ghcr.io/your-org/your-app:v1.0.0 .
docker push ghcr.io/your-org/your-app:v1.0.0
# Authentication uses GitHub credentials (e.g., a personal access token),
# not a separate registry-specific account:
docker login ghcr.io -u your-username --password-stdin
Breaking Down the GitHub Packages Example
Each example uses the ecosystem's own completely standard, familiar tooling — `npm publish` and `docker push` work exactly as they would for any other registry — with the only difference being the registry URL configured beforehand (GitHub's registry instead of the ecosystem's default public one). The final `docker login` command demonstrates the key integration point: authentication happens using GitHub's own credential system (a personal access token, in this case), rather than requiring a completely separate account and login for a dedicated package registry.
How GitHub Packages Is Used on Real Engineering Teams
- Companies with internal, proprietary libraries shared across multiple internal projects commonly use GitHub Packages specifically to avoid managing a separate private registry service and its own access control system.
- CI/CD pipelines built with GitHub Actions frequently publish build artifacts (like Docker images) directly to GitHub's container registry (ghcr.io) as part of an automated deployment workflow, benefiting from seamless, automatic authentication within the same platform.
- Organizations standardizing on GitHub for both source code and internal package distribution appreciate having one consistent permission model to manage, rather than separate access controls for code repositories and package registries.
- Open-source maintainers of genuinely public packages still typically publish to the ecosystem's dedicated public registry (like npm's registry) as their primary distribution channel, since that's where the broader community already expects to find them.
GitHub Packages Interview Questions and Answers
Q1. What is GitHub Packages, and how does its authentication model differ from a dedicated public package registry?
It's a package hosting service integrated with GitHub, supporting multiple ecosystems like npm, Docker, and Maven. Unlike a dedicated public registry requiring its own separate account, GitHub Packages uses the same GitHub authentication and repository/organization permissions already governing the associated code, avoiding a separate access-control system.
Q2. When would GitHub Packages be a better choice than publishing to npm's public registry or Docker Hub?
GitHub Packages is especially well suited for private or internal packages — shared internal libraries, private container images for internal deployment — where tight integration with existing GitHub repository permissions is a genuine advantage. For a genuinely public, widely distributed open-source package, the ecosystem's dedicated public registry remains the better choice, since that's where most users of that ecosystem already look.
Q3. How would you publish a Docker image to GitHub's container registry?
Build and tag the image with GitHub's container registry address (ghcr.io) instead of Docker Hub's default, then use the standard docker push command — for example, docker push ghcr.io/your-org/your-image:tag — after authenticating using GitHub credentials such as a personal access token.
GitHub Packages Quiz: Test Your Understanding
1. How does GitHub Packages handle authentication for publishing and accessing packages?
- It requires a completely separate account unrelated to GitHub
- It uses the same GitHub authentication and repository/organization permissions
- It has no authentication at all
- It only works with SSH keys, never tokens
Answer: B. It uses the same GitHub authentication and repository/organization permissions
Explanation: GitHub Packages is tightly integrated with GitHub's existing authentication and permission model, avoiding the need for a separate registry-specific account or access-control system.
2. Which of the following package ecosystems does GitHub Packages support?
- Only npm
- npm, Docker, Maven, NuGet, and others
- Only Docker
- None — GitHub Packages is a documentation-only feature
Answer: B. npm, Docker, Maven, NuGet, and others
Explanation: GitHub Packages supports multiple major package ecosystems side by side, including npm, Docker (via ghcr.io), Maven, NuGet, RubyGems, and more.
3. For a genuinely public, widely distributed open-source package, which is generally the better publishing choice?
- GitHub Packages, always
- The ecosystem's dedicated public registry (like npm's registry or Docker Hub)
- Neither — public packages cannot be published anywhere
- A private GitHub repository with no registry
Answer: B. The ecosystem's dedicated public registry (like npm's registry or Docker Hub)
Explanation: For broad, public distribution, the ecosystem's dedicated public registry remains the better choice, since that's where the vast majority of that ecosystem's users already look by default; GitHub Packages shines more for private/internal use cases.
Common Mistakes When Using GitHub Packages
- Assuming GitHub Packages is meant to fully replace dedicated public registries for widely distributed open-source packages, when it's better suited for private/internal use cases.
- Setting up a separate authentication system for GitHub Packages, not realizing it integrates directly with existing GitHub credentials and permissions.
- Forgetting to configure the correct registry URL for a given ecosystem's tooling before publishing, resulting in the package being sent to the wrong (default public) registry instead.
- Not scoping npm packages correctly (under an org/user namespace) when GitHub Packages requires it, causing publish failures.
GitHub Packages: Exam-Ready Quick Notes
- GitHub Packages: integrated package registry supporting npm, Docker (ghcr.io), Maven, NuGet, and more.
- Authentication: uses existing GitHub credentials and repository/organization permissions, not a separate account.
- Best for: private/internal packages tightly scoped to existing GitHub permissions.
- Public, widely-distributed packages: generally better published to the ecosystem's dedicated public registry.
GitHub Packages: Key Takeaways
- GitHub Packages provides a unified, multi-ecosystem package registry tightly integrated with GitHub's existing authentication and permissions.
- It's particularly valuable for private or internal packages, avoiding the need to manage a separate registry account and access-control system.
- For genuinely public, widely distributed packages, a dedicated ecosystem-specific public registry generally remains the better distribution channel.
Frequently Asked Questions About GitHub Packages
Q1. What is GitHub Packages?
It's a package hosting service built into GitHub, supporting multiple package ecosystems — npm, Docker, Maven, NuGet, and others — allowing you to publish and consume versioned packages directly alongside your source code repositories.
Q2. How is authentication for GitHub Packages different from a dedicated registry like npm's public registry?
GitHub Packages uses the same GitHub credentials and repository/organization permissions you already have, rather than requiring a completely separate account and access-control system specific to a dedicated package registry.
Q3. When should I use GitHub Packages instead of a public registry like Docker Hub?
GitHub Packages is especially useful for private or internal packages that need to stay tightly scoped to your organization's existing GitHub permissions. For a genuinely public, widely distributed open-source package, a dedicated public registry is generally still the better choice.
Q4. How do I publish a Docker image to GitHub Packages?
Tag your image with GitHub's container registry address (ghcr.io) instead of Docker Hub's default, authenticate using your GitHub credentials, and run the standard docker push command, for example: docker push ghcr.io/your-org/your-image:tag.
Q5. Do I need to learn new tools to publish to GitHub Packages?
No. Each ecosystem uses its own completely standard, familiar publishing tools — like npm publish for JavaScript packages or docker push for container images — you just configure them to point at GitHub's registry URL instead of the ecosystem's default one.
Summary
GitHub Packages is an integrated package hosting service supporting multiple ecosystems — npm, Docker (via `ghcr.io`), Maven, NuGet, RubyGems, and more — directly alongside GitHub's existing repository infrastructure. Its key advantage is authentication: rather than managing a separate account for a dedicated registry, GitHub Packages uses the same GitHub credentials and repository/organization permissions already governing associated source code, making it especially well suited for private or internal packages that need tight, consistent access control. Publishing uses each ecosystem's completely standard, familiar tooling (`npm publish`, `docker push`), just pointed at GitHub's registry URL instead of the ecosystem's default public one. For genuinely public, widely distributed open-source packages, a dedicated public registry like npm's registry or Docker Hub generally remains the better choice, since that's where most of that ecosystem's users already look by default.