Scaling SaaS: How We Built Two Products from One Codebase

Jan 19, 2026

Authors

Adithya
Adithya

Founding Engineer

The Problem: Building a multi-product SaaS platform? You face a brutal choice: Share everything, duplicate everything, or over-abstract. We needed a better way.

Scaling SaaS: How We Built Two Products from One Codebase

Scaling SaaS: How We Built Two Products from One Codebase

The Problem

Building a multi-product SaaS platform? You face a brutal choice:

  • Share everything: Tight coupling, regression nightmares
  • Duplicate everything: Maintenance hell, API drift
  • Over-abstract: Complexity kills velocity

We needed a better way.

Our Solution: Strategic Separation

At Youkti, we power two distinct product suites—Account Research and Competitive Intelligence—from a single codebase using a hybrid architecture:

  • Centralized: API integration, business logic, types
  • Isolated: UI components, domain features, UX

Result: 29 shared action files, 26 independent UI components, zero conflicts.

The Architecture

Shared Kernel (Business Logic)

typescript
/boards/
├── (actions)/ // 29 files - Single source of truth
│   ├── fetchMoreBoards.ts
│   ├── searchBoards.ts
│   ├── assignActions.ts
│   └── productAnalysis.ts
├── (types)/ // Shared contracts
│   └── Board.d.ts

One API change = Both products updated instantly.

Domain-Specific UI

typescript
/account-research/boards/ // Sales-focused UX
/competitive-intelligence/boards/ // Marketing-focused UX

Each team iterates independently. Zero merge conflicts.

The Impact

MetricResult
API Updates1-2 hours (both modules)
UI Changes2-4 hours (zero cross-impact)
Bug Reduction30-50% fewer API bugs
Dev Velocity2x faster for UI iterations
Code Reuse29 shared files vs. 58 duplicates

Key Technical Decisions

1. Import Strategy

Both modules import shared logic:

typescript
import { createNewBoard } from "@/boards/(actions)/newBoard";
import { Board } from "@/boards/(types)/Board";

But own their UI:

typescript
import { NewBoardModal } from "./NewBoardModal"; // Module-specific

2. Domain Extensions

Account Research adds list management:

typescript
import { fetchLists } from "@/account-research/leads-prospects/actions";

Competitive Intelligence adds battle cards—without touching shared code.

3. Type Safety

Shared TypeScript contracts prevent drift:

typescript
export interface Board {
  id: string;
  category: "comp_intel" | "account_research";
  // Enforced across both modules
}

Implementation Reality

Time Investment:

  • From scratch: 6-9 weeks
  • Refactoring existing: 4-6 weeks

Ongoing Savings:

  • 40-60% reduction in API maintenance
  • Parallel development = no bottlenecks
  • Independent deployments = faster shipping

What We Learned

Best Practices:

  • Separate business logic from presentation ruthlessly
  • Duplicate UI components without guilt
  • Enforce type safety at boundaries
  • Measure velocity and bug rates

Pitfalls to Avoid:

  • Premature abstraction
  • Shared UI components "just because"
  • Skipping documentation
  • Ignoring potential drift

The Bottom Line

Strategic duplication beats premature abstraction.

By centralizing what matters (APIs, types, business logic) and isolating what changes (UI, UX, domain features), we achieved:

  • 2x faster UI iterations
  • 50% fewer API-related bugs
  • Zero cross-team merge conflicts
  • Independent product evolution
Get Started Today

Execute from day one.
Not after weeks of setup.