comparison

Open-source vs SaaS: simplifying code differentiation with git

the verdict

Of the four common strategies — a private fork, an enterprise branch, private submodules, and per-tier feature flags in one repo — only the last two scale past a small team, and flags-in-one-repo is the only one where every fix lands in every edition automatically. Forks and long-lived branches optimize for week one and tax every week after.

connect a repo

Selling a hosted version of an open-source project forces a recurring question: how do you keep the open code and the commercial code apart without paying for that separation every week? Teams reach for four strategies, and most learn the hard way that only some survive contact with reality.

The four worth comparing are a private fork, a long-lived enterprise branch, private submodules or packages, and per-tier feature flags in one repository. The differences between them are not stylistic — they decide whether a bugfix reaches every edition automatically or by hand.

96%of commercial codebases contain open-source components — the boundary between 'your open code' and 'your commercial code' already runs through almost every product.Source: Synopsys Open Source Security and Risk Analysis Report, 2023

Strategy 1: the private fork

Fork the public repo, add paid features privately, merge upstream 'regularly'. In practice the merges decay from weekly to quarterly to never, because every divergence makes the next merge worse. The fork also poisons community trust subtly: contributors sense that the public repo is a mirror, not the product.

Strategy 2: the enterprise branch

Same repo, long-lived branch for the paid edition. Better than a fork — at least the history is shared — but the branch still accumulates conflicts, and CI has to build and test two diverging lines forever. Release day means rebasing the paid branch onto the release tag and praying.

Strategy 3: private submodules / packages

Keep genuinely proprietary code in a private package the commercial build imports. This is a sound pattern — GitLab and many open-core companies use a variant of it — but on its own it answers only 'where does secret code live', not 'which edition enables what'. You still need a packaging layer that says what each edition turns on.

Strategy 4: one repo, tiers as flag config

The differentiation moves out of git topology entirely. Main is the only long-lived line; tiers (open-source, saas, pro) are named configurations; each feature that differs is a flag with per-tier values; builds read generated config. Git does what it's good at — one history — and packaging becomes a reviewable data file.

Every bugfix reaches every edition at the next build, by construction. The public repo is the real product, which keeps contributors and auditors honest. And you can combine this with strategy 3 for the rare truly-private module: flags decide activation, the private package holds the secret bits.

The comparison in one line

Forks duplicate history, branches duplicate effort, submodules isolate secrets, and per-tier flags isolate decisions. You want decisions isolated — that's the part that changes with your pricing page. tier·dev manages exactly that layer: the tiers, the flags, and the generated per-tier config you commit.

Four ways to keep open-source and SaaS code apart

strategywhat it isolatesevery fix reaches every edition?
private forkduplicates historyno — manual upstream merges that decay
enterprise branchduplicates effortno — backport + rebase per release
private submodules / packagesisolates secretspartly — needs a packaging layer on top
per-tier flags in one repoisolates decisionsyes — by construction, at the next build

frequently asked

Doesn't GitLab famously use a separate EE codebase?
They famously moved away from it — merging CE and EE into a single codebase in 2019 because maintaining two was, in their words, a drag on velocity. The single-repo direction is the lesson, not the exception.
Is a monorepo the same idea?
Related but orthogonal. A monorepo co-locates many projects; tier-flagging packages one project many ways. You can do either without the other.
What belongs in a private package rather than behind a flag?
Code whose mere visibility is the problem: licensed third-party integrations, security-sensitive logic, partner work under NDA. Everything else ships dark behind a flag.

Published June 10, 2026 · Last updated June 16, 2026

ready to try tier·dev?

connect a repo