An architectural exercise exploring a fork + submodule + re-export strategy for consuming upstream repositories while maintaining full control over updates.
This project demonstrates an alternative to traditional forking. Instead of forking and dealing with merge conflicts, this architecture uses control points that let you decide when, what, and how upstream changes affect your codebase.
The upstream being consumed is vercel-labs/workflow-builder-template.
Your App ──▶ Re-export Layer ──▶ Git Submodule ──▶ Upstream Repo
(lib/workflow/) (your fork) (external)
│ │
WHAT to expose WHEN to update
HOW to adapt (commit-locked)
Three layers, two control points:
- Submodule (your fork): Locked to a specific commit. You choose when to pull upstream changes.
- Re-export layer: Selectively exposes components. You choose what your app sees and can wrap/adapt behavior.
- Your app: Imports from the re-export layer, isolated from upstream churn.
Supporting tooling handles dependencies and migrations:
check-deps.cjs- Ensures your dependencies match upstreamsync-migrations.cjs- Syncs database migrations with safety checks
Control points beat merge conflicts.
Traditional forks have a fundamental problem: merge conflicts are unpredictable, time-pressured, and require understanding both codebases simultaneously. You're stuck mid-merge, forced to resolve before you can continue.
This architecture inverts that:
| Traditional Fork | This Architecture |
|---|---|
| Conflicts happen to you | You choose when to sync |
| Resolve under pressure | Investigate at your pace |
| Discover problems mid-merge | Discover problems via warnings |
| Broken state until resolved | Working state preserved |
The complexity doesn't disappear—it's moved to control points where you can deal with it on your terms. Scripts warn you about deletions, modifications, and conflicts. You decide how to proceed.
| Document | Description |
|---|---|
| docs/FORK_STRATEGY.md | Full architecture and setup |
| docs/FORK_STRATEGY_ANALYSIS.md | Honest analysis of tradeoffs and flaws |
| docs/FORK_ALTERNATIVES.md | Simpler alternatives (when to use them) |
| docs/MIGRATION_SYNC.md | Database migration strategy and edge cases |
| docs/ARCHITECTURE_ASSESSMENT.md | Overall assessment and conclusions |
git clone --recurse-submodules <repo-url>
cd workflow-app
pnpm install
pnpm docker:dev
pnpm sync-migrations
pnpm db:migrate
pnpm dev| Script | Description |
|---|---|
pnpm sync-upstream |
Pull latest from upstream |
pnpm sync-check |
Preview upstream changes |
pnpm check-deps |
Verify dependencies match |
pnpm sync-migrations |
Sync migrations (with safety checks) |
pnpm sync-migrations:check |
Preview migration changes |
pnpm db:migrate |
Apply migrations |
This isn't about avoiding complexity. It's about choosing when and how to deal with it.
Merge conflicts are reactive. Control points are proactive. This architecture demonstrates that with some upfront investment in tooling, you can consume an active upstream while maintaining stability—and never be surprised by a conflict at an inconvenient time.