why branches fail as a packaging mechanism
Git branches answer 'what changed, when, by whom'. Editions ask a different question — 'who is this feature for?' — and a long-lived branch is a terrible place to store the answer: it drifts, it conflicts, and it hides the edition difference inside a diff only one engineer can read.
Flags invert that. The difference between your community edition and your cloud edition becomes a column of on/off values that anyone — engineering, support, a prospective customer doing due diligence — can read in one screen.
what stays out of the public repo
Most paid code can ship dark: present in the repository, disabled by flag in the open-source build. For the small remainder where visibility itself is the problem — licensed integrations, partner work under NDA — keep one thin private package that only the SaaS build imports, gated by the same flag. That's one private module, not a private fork of your whole product.
If a feature must be physically absent from the open-source artifact, point your bundler's compile-time defines at the resolved tier config and dead-code elimination strips the gated modules from that build entirely.
where tier·dev fits in the loop
tier·dev is the bookkeeping layer: connect the GitHub repo, define the tiers, manage flags in a matrix with per-tier overrides, and copy the generated tiers.json, tiers.yaml, or dependency-free flags.ts into the repo. There is no runtime SDK and no network call in your hot path — the config is yours, committed and reviewed like any other code.
how it works
- 01
connect the repository
Sign in to tier·dev and connect your GitHub repo via OAuth — it reads repo metadata only, never your source code.
- 02
name your tiers
Create the editions you actually ship: open-source, saas, pro. Tiers are labels on one codebase, not branches.
- 03
flag the first difference
Create a flag like PRO_DASHBOARD_ENABLED with default off, then override it on for the saas tier.
- 04
commit the generated config
Copy the generated tiers.json (or yaml, or flags.ts) into the repo and gate the feature with a one-line check.
- 05
parameterize CI
Build each edition from the same commit with PRODUCT_TIER set — every fix lands in every edition on the next build.
frequently asked
- can't open-source users just flip the paid flags on?
- Self-hosters who flip flags were never the customer — what a SaaS sells is hosting, updates, SSO that's supported, and someone to call. Open-core companies have shipped honestly-flagged code for years; if a feature truly must be absent, strip it at build time from the same config.
- do I need to migrate off my enterprise branch first?
- No — merge it back one feature at a time. Pick a divergent feature, wrap it in a flag on main, delete it from the branch. Most teams retire the branch within a few sprints without freezing releases.
- does this add a runtime dependency to the open-source build?
- None. The open-source distribution reads a committed config file at build or boot. There's no tier·dev SDK and no network call — clones of your repo work offline, forever.
Last updated June 12, 2026