How to Build Open Source People Actually Use — Not Just Another GitHub Repository
- Published on
- Reading time
- 12 min read
Publishing code to GitHub is easy. The harder part is helping developers discover a project, understand it, trust it, install it, and keep using it. These are the lessons I learned building and maintaining real open-source products.
In the previous article, I wrote about the moment I stopped seeing my open-source work as a collection of separate repositories and started seeing an ecosystem.
But before you can have an ecosystem, you need at least one project people genuinely want to use.
Publishing a repository on GitHub is easy.
Getting someone who does not know you to discover the project, understand it, trust it, install it, and eventually rely on it in a real application is a very different problem.
I have built a lot of open-source software over the years. Some projects gained traction faster than others, and the difference was not always code quality.
Sometimes the project I considered technically stronger was not the one people adopted.
Sometimes a much smaller tool spread faster simply because it solved one clear problem at exactly the right level.
That changed the way I think about open-source success.
A repository is not the product.
The code is part of the product.
The product is the full experience that starts when a developer first hears the name and ends when the software is quietly doing useful work inside their application.
Be the first real user of your project
The projects I keep maintaining the longest are usually projects I needed myself.
That is not because my needs matter more than anyone else's. It is because real use exposes problems that theoretical development never will.
When you use your own package inside a production application, you discover things very quickly:
- Is the API annoying in daily use?
- Are there configuration steps that should not exist?
- Do you need to reread your own documentation every time?
- Does a small upgrade break too much?
- Is the naming obvious?
- Do the error messages actually help?
There is a big difference between:
“The feature works.”
and:
“I am happy to use this feature every day.”
Dogfooding has become one of my most useful quality checks for open source.
If I do not enjoy using the tool I built, why should another developer be excited about adopting it?
Start with the problem, not the feature list
One of the easiest ways to ruin a small project is to add features too quickly.
You begin with a simple idea.
Then someone asks for an option.
Someone else wants an integration.
Soon there is a dashboard, an API, events, drivers, and eventually a plugin system.
A few months later, the original problem the project was good at solving is buried under configuration.
I have fallen into this line of thinking more than once.
Today I try to ask a much simpler question:
What is the one problem this project should be exceptionally good at solving?
If I cannot answer that in one sentence, there is usually a positioning problem before there is an engineering problem.
A project does not need to do everything.
It needs to do something important very well.
Your README is often the real homepage
For many open-source projects, the README is the actual homepage whether we planned it that way or not.
A developer may arrive from Google, GitHub search, an Awesome list, a newsletter, or a link from a friend.
Very often, the first thing they see is the README.
Yet many READMEs start like this:
composer require vendor/package
before explaining why anyone would want the package in the first place.
I prefer to answer four questions first:
What is this?
What problem does it solve?
Who is it for?
What is the fastest way to see the result?
Installation can come after that.
If a developer has to scroll through half the page to understand why the repository exists, we already created friction.
Reduce time to the first useful result
There is an unofficial metric I like to think about:
Time to First Useful Result.
How long does it take from discovering the project to seeing something genuinely useful happen?
Not until the developer finishes the documentation.
Not until they understand every architectural decision.
Just until they reach the moment where they think:
“Okay. I understand why this is useful.”
Every extra setup step gives someone another opportunity to leave.
If installation requires:
- Installing the package.
- Publishing configuration.
- Editing three files.
- Registering a provider.
- Running a migration.
- Copying a component.
- Updating JavaScript.
- Rebuilding assets.
then every one of those steps needs to justify its existence.
This is not about hiding complexity.
It is about asking whether the user should have to experience that complexity at the beginning.
Give people a good default
Developers like flexibility.
They do not necessarily want to make twenty decisions before the project runs.
One of the things I have always appreciated in Laravel is that it has opinions. You can change many of them, but you do not need to design your whole architecture before writing the first feature.
I try to bring the same idea into my own tools.
Give me a default that works.
Then let me replace it when I have a real reason to.
Instead of saying:
“Choose one of seven drivers and provide forty lines of configuration.”
start with the choice that works for most people.
Configuration should often be an escape hatch, not an entrance requirement.
Good documentation is organized around tasks
A developer rarely opens the docs thinking:
“I would like to learn every method on this class.”
They are usually thinking:
“I need to do X.”
That is why I increasingly prefer task-oriented documentation over documentation that mirrors the code structure too closely.
For example:
- How to install
- How to create your first resource
- How to customize authentication
- How to connect an MCP server
- How to add persistent memory
- How to deploy
An API reference can still exist for people who need detail.
But one complete example that solves a real task is often more valuable than ten pages describing individual options.
Never make users guess the state of the project
A common GitHub problem is finding a repository that looks useful but gives you no idea what state it is in.
Is it still maintained?
Does it support the latest framework version?
Is it something people use in production?
Is it only a proof of concept?
The last commit may be a year old because the project is stable.
Or the last commit may have been yesterday and the project is still an experiment.
Users should not have to guess.
Make the basics obvious:
- Supported versions
- Current project status
- Upgrade policy
- License
- Release history
If you stop maintaining a project, say that too.
A clearly archived repository is better than a project that looks alive but has silently been abandoned.
Compatibility eventually matters more than the exciting new feature
Your responsibility changes when people begin using the project for real work.
Before that point, you can rewrite everything on Thursday because you found a cleaner architecture on Wednesday night.
Once the package is in other people's production systems, breaking changes create costs you do not pay alone.
I learned to respect this more over time.
It does not mean projects should stop evolving.
It means the value of the following increases as adoption grows:
- Semantic versioning
- Migration guides
- Deprecation periods
- Changelogs
- Backward compatibility
A developer needs to trust that an upgrade will not turn the beginning of their workday into an unexpected debugging session.
That trust can become more valuable than the next feature.
Issues are product research, not just support tickets
GitHub Issues can be an excellent source of product research, especially when the same questions keep appearing.
If three people ask the same question, maybe the problem is not that they failed to read the documentation.
Maybe the documentation is not clear enough.
If many users need the same workaround, maybe the abstraction is incomplete.
If everyone makes the same configuration mistake, maybe the API itself deserves another look.
The most valuable feedback is not always:
“Great project!”
Sometimes it is the annoying issue that exposes a real design problem.
Say no more often than you say yes
This is one of the hardest parts of maintaining open source.
Someone took the time to open an issue or feature request. Naturally, you want to help.
But every feature that enters the project becomes something you may need to:
- Maintain
- Test
- Document
- Keep backward compatible
- Support when it breaks
A feature that takes two hours to implement can create a maintenance commitment that lasts years.
So the question is not only:
Can I build this?
It is also:
Should this be part of this project at all?
Sometimes the right answer to a feature request is that the problem is outside the scope of the project.
That is not ignoring the user.
It is protecting the product.
Distribution is part of engineering
For a long time, I believed some version of this:
If the project is good enough, people will find it.
That is only partially true.
There are thousands of excellent projects that almost nobody knows exist.
Distribution is not something developers need to be embarrassed about.
Publishing to Packagist, npm, pkg.go.dev, or the appropriate ecosystem matters.
Searchable documentation matters.
A clear GitHub description matters.
Relevant directories and Awesome lists can matter.
Writing a real technical article about the problem that caused the project to exist can matter.
Connecting the project to related tools when the relationship is useful can matter.
The problem is not marketing.
The problem is marketing that has nothing useful behind it.
Stars are not the only metric
GitHub stars are nice.
I enjoy watching them increase too.
But a star does not necessarily mean someone is using the software.
There are repositories with thousands of stars where most people who clicked the button never installed the project once.
There are other signals I find more interesting:
Do people come back to the documentation?
Are there real installations?
Do contributors begin appearing?
Do issues evolve from “How do I install this?” into deeper usage questions?
Do people build integrations you never asked them to build?
Does someone explain the project to another developer before you get the chance?
Those are signs that a repository is becoming something with actual users.
Community starts with one person
The word community sometimes makes us imagine a Discord server with thousands of members.
But a community can begin with one user who comes back twice.
Then someone opens a pull request.
Someone fixes a typo in the docs.
Eventually someone answers an issue before you do.
Those moments look small, but they matter.
People contribute to projects where contribution feels welcome.
A clear contributor guide helps.
Good issue descriptions help.
Respectful responses help.
An architecture people can understand helps.
Those things are often more important than adding a “community driven” badge to the README.
Open source is a long-term contract
Creating a repository is free.
Maintaining one is not.
It takes time.
It takes focus.
And sometimes it creates its own mental load when dozens of issues are waiting while you are already responsible for other products.
That is another reason I have started thinking more about an ecosystem and less about increasing the number of repositories I own.
The goal is not to have the largest possible project list.
The goal is to keep projects that are useful, clear, and worth maintaining.
Sometimes merging two projects is better than maintaining both.
Sometimes archiving is better than rewriting.
Sometimes not building the project in the first place is the best engineering decision.
Before you publish your next open-source project
Today, if I build a new open-source project, there are a few questions I like to ask before calling it ready:
Can I explain the problem in one sentence?
Have I used the project myself?
Does the README explain the value before the installation command?
Can someone reach a useful result quickly?
Is there a sensible default?
Is the documentation organized around what users want to accomplish?
Are supported versions obvious?
Am I willing to maintain this API?
Is the project meaningfully different from what already exists?
And would I still be happy maintaining it three years from now?
That last question matters more than it sounds.
Sometimes success means people actually use what you built.
When that happens, you get to live with the decisions you made during the first week for much longer than you expected.
In the end
The best open-source projects, to me, are not the ones with the most code.
They are the ones that almost disappear while you use them.
They solve the problem.
They behave the way you expect.
They explain themselves clearly.
And they do not force you to think about them more than necessary.
If you want people to use your project, do not begin by trying to convince them the code is impressive.
Begin by making their work easier.
Solve a real problem.
Make the first experience simple.
Write documentation that respects the developer's time.
Protect their trust as the project grows.
And pay attention to what happens after the code leaves your machine and starts running inside projects you know nothing about.
That is the point where your project stops being just another GitHub repository.
It becomes a product.
Comments (0)