Repository Structure Decision: BFF Implementation¶
Date: December 2025
Status: Architecture Decision Record
Related: BFF-Implementation-Plan.md
Question¶
Should bast-bff be implemented in the same repository as bast-admin-ui (monorepo) or in a separate repository?
Context¶
- Current State:
bast-admin-uiis a React/TypeScript frontend in its own repository - New Component:
bast-bffis a Node.js/TypeScript BFF layer using tRPC - Key Benefit: tRPC provides end-to-end type safety between frontend and BFF
- Team: Frontend team will own the BFF layer
Options¶
Option A: Monorepo (Same Repository)¶
Structure:
bast-admin-ui/
├── apps/
│ ├── admin-ui/ # React frontend (current codebase)
│ │ ├── src/
│ │ ├── package.json
│ │ └── vite.config.ts
│ │
│ └── bff/ # Node.js BFF
│ ├── src/
│ ├── package.json
│ └── tsconfig.json
│
├── package.json # Root workspace config
├── pnpm-workspace.yaml # or npm/yarn workspaces
└── turbo.json # Turborepo (optional)
Option B: Separate Repositories¶
Structure:
bast-admin-ui/ # Frontend repo
├── src/
├── package.json
└── ...
bast-bff/ # BFF repo (separate)
├── src/
├── package.json
└── ...
Comparison Matrix¶
| Criteria | Monorepo (Option A) | Separate Repos (Option B) |
|---|---|---|
| Type Sharing | ✅ Native - shared types via tRPC | ⚠️ Requires package publishing or git submodules |
| Development Workflow | ✅ Single clone, single install | ⚠️ Multiple repos to manage |
| CI/CD Complexity | ⚠️ More complex (need to detect changes) | ✅ Simpler (independent pipelines) |
| Deployment Independence | ⚠️ Coupled (but can be decoupled) | ✅ Fully independent |
| Code Changes | ✅ Atomic commits across frontend + BFF | ⚠️ Requires coordination across repos |
| Team Collaboration | ✅ Easier for frontend team | ⚠️ More coordination needed |
| Build Times | ⚠️ Slower (builds both) | ✅ Faster (builds independently) |
| Dependency Management | ✅ Shared dependencies | ⚠️ Duplicate dependencies |
| Testing | ✅ Can test integration easily | ⚠️ Harder to test integration |
| tRPC Benefits | ✅ Maximum benefit (shared types) | ⚠️ Reduced benefit (types across repos) |
Detailed Analysis¶
Option A: Monorepo - Pros¶
- Perfect tRPC Integration
- Types are shared automatically
- No code generation needed
- TypeScript can reference types directly
-
Changes to BFF types immediately reflected in frontend
-
Atomic Changes
- Can update frontend and BFF in a single commit
- Easier to maintain API contracts
-
Better for refactoring
-
Simplified Development
- Single
npm installorpnpm install - One repository to clone
-
Easier onboarding for new developers
-
Better DX (Developer Experience)
- IDE can navigate between frontend and BFF code
- Easier to understand the full stack
-
Better autocomplete and type checking
-
Shared Code
- Can share utilities, types, constants
- Single source of truth for shared logic
Option A: Monorepo - Cons¶
- CI/CD Complexity
- Need to detect which packages changed
- May build/test both when only one changed
-
Requires tools like Turborepo, Nx, or custom scripts
-
Repository Size
- Larger repository
-
Longer clone times
-
Deployment Coupling
- Frontend and BFF deployments are in same repo
- Need careful branch management
-
Can be mitigated with proper CI/CD setup
-
Access Control
- Harder to restrict access to specific parts
- Everyone with repo access sees everything
Option B: Separate Repos - Pros¶
- Independent Deployment
- Deploy frontend and BFF independently
- Different release cycles
-
Easier to scale teams
-
Simpler CI/CD
- Each repo has its own pipeline
- No need to detect changes
-
Faster builds (only builds what changed)
-
Clear Boundaries
- Clear separation of concerns
- Easier to understand ownership
-
Better for large teams
-
Access Control
- Can restrict access per repository
- Different teams can own different repos
Option B: Separate Repos - Cons¶
- Type Sharing Complexity
- Need to publish BFF types as npm package
- Or use git submodules (complex)
-
Or generate types (defeats tRPC purpose)
-
Development Friction
- Need to clone multiple repos
- Need to manage multiple dependencies
-
Harder to make coordinated changes
-
Reduced tRPC Benefits
- Types may not be perfectly synced
- Need to regenerate types when BFF changes
-
Less seamless developer experience
-
Coordination Overhead
- Need to coordinate changes across repos
- API changes require PRs in multiple repos
- Harder to maintain consistency
Recommendation: Option A (Monorepo)¶
Rationale¶
Given your specific context:
- tRPC is the Key Benefit
- The primary reason for choosing BFF pattern is end-to-end type safety
- Monorepo maximizes this benefit
-
Separate repos would require workarounds that reduce tRPC's value
-
Frontend Team Ownership
- Since frontend team owns the BFF, monorepo makes sense
- Easier collaboration within the team
-
No cross-repo coordination needed
-
Small to Medium Team
- Monorepo works well for smaller teams
-
Less overhead than managing multiple repos
-
Rapid Development
- Can iterate quickly on both frontend and BFF
- Changes are atomic and easier to test
Implementation Approach¶
Recommended Structure:
bast-admin-ui/ # Monorepo root
├── apps/
│ ├── admin-ui/ # React frontend
│ │ ├── src/
│ │ ├── package.json
│ │ └── vite.config.ts
│ │
│ └── bff/ # Node.js BFF
│ ├── src/
│ ├── package.json
│ └── tsconfig.json
│
├── packages/
│ └── shared/ # Shared types & utilities (optional)
│ ├── types/
│ └── package.json
│
├── package.json # Root workspace
├── pnpm-workspace.yaml # Workspace config
├── turbo.json # Turborepo config (optional)
└── .github/
└── workflows/
└── ci.yml # CI/CD with change detection
Tools:
- Package Manager: Use
pnpmworkspaces ornpmworkspaces - Build Tool (Optional): Turborepo or Nx for faster builds
- Type Sharing: Direct TypeScript imports (no package publishing needed)
Alternative: Hybrid Approach¶
If you need deployment independence but want type sharing:
Structure: - Keep repos separate - Use tRPC with code generation - Publish BFF types as npm package - Frontend imports types from package
Trade-off: More setup complexity, but maintains deployment independence.
Migration Path¶
If Choosing Monorepo:¶
-
Phase 1: Restructure Current Repo
-
Phase 2: Add BFF
-
Phase 3: Set Up Workspace
-
Phase 4: Configure tRPC Type Sharing
Decision Checklist¶
Choose Monorepo if: - ✅ You want maximum tRPC type safety benefits - ✅ Frontend team owns BFF - ✅ Team size is small to medium (< 10 developers) - ✅ You want rapid iteration - ✅ You're okay with slightly more complex CI/CD
Choose Separate Repos if: - ✅ You need strict deployment independence - ✅ Different teams own frontend vs BFF - ✅ You have complex access control requirements - ✅ You prefer simpler CI/CD pipelines - ✅ You're willing to trade some tRPC benefits for independence
Final Recommendation¶
For Bast Admin UI: Use Monorepo (Option A)
The benefits of seamless type sharing with tRPC outweigh the CI/CD complexity. Since the frontend team owns the BFF, a monorepo provides the best developer experience and maintains the core value proposition of the BFF pattern.
Next Steps¶
- ✅ Decision Made: Proceed with monorepo structure
- Update BFF Implementation Plan to reflect monorepo structure
- Set up workspace configuration (pnpm/npm workspaces)
- Restructure repository (move frontend to
apps/admin-ui/) - Create BFF in
apps/bff/ - Configure CI/CD with change detection
Document created for Bast Admin UI Repository Structure Decision