Recently, I discovered a bug in an npm package I was using, and I needed to fix it quickly for my project. I opened an issue, waited for a response from the maintainers, but then I realized that for some reason (that I still haven’t figured out to this day), the problem only affected me. Maybe some weird edge case conflict with another package, maybe cosmic ray interference, who knows. I also knew that forking and publishing my own version of the package could introduce problems.
The maintainers closed the issue, stating it wasn’t a bug. Fine, makes sense. Someone is (obviously) targeting my development environment but I don’t have the resources to hire a private investigator, so I decided that I wanted to address the issue. I'll walk you through my process for forking and publishing packages (mainly when you want to fix a bug in a package), and I'll share some important considerations that might make you consider your options before taking this approach.
Important note: This is something I rarely recommend, but in specific situations, it has been the best option for me. Use at your own risk, because often, this is not the best option. I'll discuss when to use this and when not to use this.
Why Fork and Publish Your Own Package?
Sometimes you need an immediate fix. Maybe you've found a critical bug that's blocking your deployment. Or perhaps, you've discovered an edge case that affects your specific use case.
FYI, when I say “publish your own package”, I don’t mean fork and open a pull request. I mean fork and re-publish the package under your own account. As I’ll discuss later, in almost all situations I do not recommend doing this.
The first time I wanted to do this, I found an edge case bug that only affected me. The maintainers wouldn't fix the bug since it would break everyone else's code, which is completely understandable and the right move on their part. So, instead of copying and pasting their code into my project, creating my own package seemed like the best option.
My Step-by-Step Process
Here's how I handle forking and publishing an npm package when I need a quick fix:
1. First, I fork the repository on GitHub. I make sure to name it clearly, usually keeping the original name with my username as a prefix. This helps me track my forks and makes it clear to others that this is a temporary fix.
2. Then I clone my fork locally:
git clone https://github.com/myusername/package-name
cd package-name3. Before making any changes, I create a new branch:
git checkout -b fix/describe-the-bug4. After making my fixes, I update the package version in package.json. I usually add a suffix to make it clear this is my fork:
{
"name": "@myusername/package-name",
"version": "1.2.3-myfix.1"
}5. Next, I make sure I have an npm account and log in:
npm login6. Finally, I publish the package:
npm publish --access public7. In my original project's package.json, I update the dependency to use my forked dependency:
{
"dependencies": {
"@myusername/package-name": "1.2.3-myfix.1"
}
}The Good Parts
This approach has several benefits that I've come to appreciate:
- You get unblocked right away
- You can tailor the package’s logic to your specific needs (if needed)
- Working with package internals helps you understand the ecosystem better
- Your fix could serve as a basis for a pull request to the original repository, if you're change fixes a known bug.
The Not-So-Good Parts
However, there are significant drawbacks that I've learned to consider carefully:
Maintenance Burden
Every forked package is technical debt. You're now responsible for keeping your fork up to date with the original package, or you risk missing important updates and security fixes. I've been burned by this more than once, finding myself stuck on an old version because updating would mean re-applying my fixes to the new version.
So, the extremely small number of times I’ve done this (two, at the time of writing this), I decided to do it because the packages were small, were unrelated to security, and based on my knowledge of the package, could be left as-is without ever updating.
Basically, I’d never do this with React, for example. I’d only do this with small packages with few dependencies where I can set it and forget that there was ever an issue without ever having to update it.
Version Conflicts
If other packages in your project depend on the original package, you might run into version conflicts. npm's dependency resolution isn't always smart enough to handle forked packages gracefully, especially if multiple packages require different versions of the original.
Security
When you fork a package, you're also taking on the responsibility for security updates. If the original package gets a security patch, you'll need to update your fork manually. This can be problematic.
Long-term Viability
What starts as a quick fix can turn into a long-term commitment. If you see it being a long term commitment, consider other options.
Better Alternatives I've Found
Before you fork, consider these alternatives that I've found helpful:
- patch-package: This tool lets you make changes to your node_modules directly and creates patches that can be version controlled and automatically applied during installation.
- Override Dependencies: Many package managers now support overrides, allowing you to force specific versions of nested dependencies without forking.
- Wait it Out: Sometimes, waiting for the maintainers to fix the issue is less work overall than maintaining a fork.
When I Do Fork (And When I Don't)
I now only fork packages when:
- The bug is critical and blocking my work
- I've already opened an issue and provided a clear reproduction
- The maintainers are unresponsive or the fix timeline doesn't align with my needs
- I'm confident I can maintain the fork until the upstream fix is available
- Or, I’m confident that this fork will almost never need maintenance
I avoid forking when:
- The bug is minor or has workarounds
- The package is complex with frequent updates
- The fix might introduce security implications
- I don't fully understand the package's internals