Ask HN: Founders who offer free/OS and paid SaaS, how do you manage your code?
I am curious as to how do you solve the problem of maintaining different offerings of your product.
1) Do you have two separate codebases for free and paid? Or do you have some sort of standard workflow where you have two different branches? 2) How do you handle updates to your product? 3) How about employee access?
Thanks in advance!
116 comments
[ 4.1 ms ] story [ 140 ms ] threadI've been running this set up for about a year [1] and it's working well. Having a single code base was a requirement before I made the project fair source [2]; the fair source ELv2 license lets me add feature gates to facilitate this, while protecting me from forks giving away EE features for free (while still allowing forks).
Updates are pushed to the SaaS offering daily. I cut self-hosted releases bi-annually unless it's for a critical fix.
[0]: https://github.com/keygen-sh/keygen-api
[1]: https://keygen.sh/blog/all-your-licensing-are-belong-to-you/
[2]: http://fair.io/
2. Your project repro actually links to the elastic license. Is there some relation between the two? Do you prefer the fairsource license over the elastic license>
2. Yes, the ELv2 will be considered a Fair Source license, because it allows contributions, redistribution, forking, etc. You can visit https://faircode.io for an idea of what Fair Source will ultimately entail (Fair Source and Fair Code will be merged eventually AFAICT).
[0]: https://github.com/getsentry/fsl.software/issues/4
[1]: https://github.com/getsentry/fsl.software/issues/2
Since Keygen was previously closed source, I didn't want to split the repo up into the ee/ directory structure that you commonly see in other open core and fair source projects. I deemed doing so as 'too risky' -- too much code churn for little benefit -- as those changes would have a direct effect on the SaaS.
Instead, I opted for ELv2 because it offered me the ability to say, "hey, I'm making this fair source, do what you want with it, just don't compete with me or remove the license gates for the paid features."
Here's some of my internal dialog i.r.t. the license choice: https://github.com/keygen-sh/keygen-api/pull/668
https://github.com/fairsource/fair.io/issues/14
But would be it practical to go for a such guy?
There are always... stupid people who use hacked software 'because the employer don't have money', but I guess someone with a skill enough to read and patch such code is fully aware how the things are working and wouldn't be doing such stupid deeds.
Not really something I'm worried about.
But if the original product grows enough to be able to reach far away markets, then it's lawyer and discovery money would grow too.
I applaud Keygen API approach, though I really hope we find a formula that makes free software become pervasive while providing financial stability to authors and maintainers.
With an API product, you also have to be picky about new features because once something is introduced, it can't be taken back (assuming you want to maintain backwards compatibility).
The reasons for OSS you list include "Bus-Factor", "Longevity", and "Continuity". I'd summarize all of those as "even if they can't do business with [company] anymore, users can continue on" - our customers also say that's very important to them.
... But what if "can continue on" means "need some of those proprietary features"? And you're not there to sell to them anymore? Or you've been acquired by private equity, started charging 10^6x, and users want out? Users aren't allowed to clone the repo, remove your proprietary code, and reimplement it with their own solution, because:
> you may not remove or obscure any functionality in the software that is protected by the license key.
Is this a thing your customers are concerned about? What do you expect them to do in such a scenario?
Maybe some kind of clause for a "Change License" in case Keygen LLC goes under, e.g. we go from ELv2 to Apache 2.0 if that happens. I'm not really sure what that'd look like right now, but I'll keep thinking on this and hopefully come up with a good answer eventually.
Outside of that, nothing is really stopping somebody from forking Keygen and reimplementing the EE features 'in-spirit' under a new code path, especially if Keygen LLC has gone bust. They just can't remove or copy the existing EE features verbatim.
I need to send your team some shirts!
More: https://twitter.com/chadwhitacre_/status/1790101820364267902
Did you write that as well or outsource it?
Projects use different licenses for enterprise and regular features. Cal does that for example.
Novu doesn’t commit their enterprise features to their codebase. And they symlink those features in. Their project is all MIT because of this.
My SaaS version of https://datasette.io is the open source version plus 76 plugins. Almost all of those plugins are themselves open source, with just a few that aren't for features that are unique to the SaaS product - things like showing how much disk space the user has used up already.
Here's what that custom plugin looks like, it's pretty thin: https://gist.github.com/simonw/114131fd9c1826f3629cc3b3dcb84...
I recommend checking out their approach, as it is pretty flexible.
https://docs.ckan.org/en/2.9/extensions/index.html
Thank you for adding this bit of info! We’ve been using this model for a while but I hadn’t come across a label for it. Now knowing this, I’m coming across a ton of great info about managing/sustaining these product families.
<div class='hidden-paid-user'>Click here to get our paid service</div>
You would still have server code enforce the subscription level rules because a malicious user could circumvent any client-based rules. How exactly you do both will depend on the framework your saas uses.
In this example as I recall most of the enterprise code was just activation code, so a properly motivated individual could probably figure out how to turn on some of the enterprise features, but most people won't bother to figure out how to do their own builds, and it's more work then finding the secret env variables in an open repo.
It's a little bit painful at times because changes that cover both code bases need two commits, and it isn't uncommon for someone to forget or commit the wrong submodule pointer. But depending on the team, it can work.
Not for everyone, just including it as an option I haven't seen mentioned in other comments.
Our “git” is Plane[1], which is by design fairly unopinionated and general. Our “github” is Jamsocket[2], which is more opinionated about deployment, observability, etc.
We use the open source version of Plane in Jamsocket, and build on top of it in a separate (proprietary) codebase.
[1] https://plane.dev
[2] https://jamsocket.com
Discussion of split codebases happens around the 41 minute mark
And each plugin has a concept called install constraints. They consist of app, tier, and the role of the user provisioning the account.
Based on the right combination, certain plugins get auto installed and the user can enable/disable optional plugins/features.
Upon installation, the plug-in module has a “lifecycle” module with callbacks for install, uninstall, after_install, etc.
In those, we insert db metadata (pages, folders, menu items, etc) related to that plugin.
All is written in elixir.
1: https://simplyscholar.com
We will have samples up in a couple weeks. But stay in touch! ashish@simplyscholar.com
This approach has really made the private fork much more maintanable.
[0] https://www.getoutline.com
[0] https://github.com/outline/outline
I'm always unsatisfied with the number of steps to achieve that (and the total CI time required), but maybe it's unavoidable.
If you include open source and proprietary components in the same repo I will be annoyed. Especially if it is not very clear how the licensing is split, or if the proprietary stuff is split in multiple folders.
If you don't have instructions, or it is otherwise unreasonably difficult to build the open-source only version, I will be very annoyed.
If your "open source" code is directly linked to the proprietary parts, and it requires non-trivial changes to your code in order to build without the proprietary components, I don't consider your project open source, no matter how much you plaster "open source" on your marketing materials. And it's even worse if the license is unclear on what the licensing situation is if you use a release that includes all these proprietary components, but they are turned off because you don't have a license key.
We had started off by using a series of private repos for our non-OSS features. At build time, we had a pretty complicated suite of build tooling that took all of the repos and integrated them and ran the integration tests. The biggest reason why Elasticsearch went to single repo with all of the enterprise software included (knowing that the OSS-focused community was going to backlash on it) was just how much of a hassle that was. It bifurcated everything and the results were that paying customers were upset the most.
For example: have an issue with the product? You could file a GitHub issue in public and it would get looked at quickly, but if you were a paying customer with an issue with one of the enterprise features, you had to file an issue with the support team because the GitHub repo was separate/private, and then support would file an issue in the private GitHub repo, and you'd lose complete visibility with it. It was even worse for free/trial users: they had to file an issue on our forums (since they didn't have an established support contact), after which they lost visibility. Integration tests were also hellish.
I later worked at another open core company, which at first maintained a separate codebase for its paid offering, and synchronized changes over from the open source product periodically, and things were much worse: a ton of bugs kept popping up and getting the paid offering out the door was always extremely slow because you were always playing catch up on the OSS offering.
You can go down the submodule route, but you end up relying on pretty complicated build tooling. If that's in your team's realm of capabilities, it's not a bad route to go. If you have no need for "OSS," then you can choose a non-OSS license that provides whatever restrictions you care about and bundle it up together, which is easier, but might dissuade certain users.
Regardless, licensing enforcement isn't really an issue if you're working on a B2B product: there are certain demographics that won't pay for your software, but they won't pay if you have licensing enforcement either. B2C can be a different story.
I'm using different implementations of interfaces for self-hosted vs commercially (my variant) hosted.
What implementations get chosen depends on environment variables.
The code is available as GPL
We started with open-source first, and added SaaS offering after ~2 years. The code base split was a natural choice. At first, I didn't want to add SaaS, because managing servers is a lot of work. But, we have a lot of requests for such service, and it makes really easy to deploy notebook online (with few clicks you have unique domain and notebook running). I'm happy with this code base split.
[0]: https://runmercury.com
[1]: https://github.com/mljar/mercury
For instance, a Git-like DAG for a config service [1] that supports history and eventually forking and merging on top of PostgreSQL. This was broken out of the larger Go codebase and is currently AGPL3 as a placeholder while I research better licenses to use.
The overall idea is the "nuts and bolts" of a small startup/SaaS app, including metrics, IAM/auth, and subscriptions via a single API and React/JS SDKs.
I hope to do a Show HN on one or both in the near future.
[1] https://github.com/tmzt/config-api
- 2 git repos, one public, one private
- Custom tooling inspired by other existing tools out there like copybara to move commits in a unidirectional flow from the private repo to the public one
The private repo had the contents of the OSS repo in a subfolder, and a unidirectional workflow where all commits flowed from the private to the public. The way the OSS repo accepted contributions was going through the normal pull request workflow on the OSS repo, then on approval the custom tooling copied the pull request into the private repository where it would go through a second round where it was tested against the private code. On merge in the private repo the commit sha of the original commit along with the original author would get injected into the new commit message and then the custom tooling would then automatically push commits in the private repo subfolder to the public OSS repo, which essentially served as a read only mirror on the main branch.
It actually worked quite well, though obviously this approach comes with some tradeoffs. Here are some of the benefits and drawbacks off the top of my head
Benefits:
- no mixing of free and proprietary code. Public users just check out the OSS repo and it’s completely free
- proprietary code is not visible to the public
Drawbacks:
- workflow slightly more complex for both end users and employees of the enterprise
- more work to mainline code by the enterprise: contributions essentially need to be reviewed twice
- it is not possible to have signed commits by OSS contributors with this workflow
Overall it ended up being a great solution for that organization but this kind of approach can only work for low traffic or easy to review repositories. Anything with a decent amount of traffic or lots of complex contributions has a risk of becoming too much overhead for the organization to double build and test pull requests
Mapzy: A simple storefinder (https://github.com/mapzy/mapzy)
Fugue: Privacy-friendly product analytics (https://github.com/shafy/fugu)