Why Monorepo?
When you're building products that span Web, Mobile, Desktop, and Backend — all sharing business logic, types, and utilities — a monorepo isn't just convenient. It's essential.
At Circuvent, our larger projects (NEXUS AI OS, Financial Analyzer, TimeCapsule) all follow a monorepo structure. Here's how we organize them.
Directory Structure
project-root/
├── packages/
│ ├── shared/ # Shared types, utils, constants
│ ├── ui/ # Shared React components
│ └── api-client/ # Generated API client
├── apps/
│ ├── web/ # Next.js web app
│ ├── mobile/ # React Native / Expo
│ ├── desktop/ # Electron app
│ └── api/ # FastAPI / Express backend
├── infra/
│ ├── docker/ # Dockerfiles
│ ├── scripts/ # Build & deploy scripts
│ └── ci/ # GitHub Actions workflows
├── docs/ # Architecture docs
├── docker-compose.yml
├── package.json # Root workspace config
└── turbo.json # Turborepo configShared Type Safety
The packages/shared directory contains TypeScript interfaces that are used across all platforms:
// packages/shared/src/types/user.ts
export interface User {
id: string;
email: string;
displayName: string;
avatar?: string;
role: 'admin' | 'user' | 'premium';
preferences: UserPreferences;
createdAt: Date;
updatedAt: Date;
}
export interface UserPreferences {
theme: 'light' | 'dark' | 'system';
notifications: boolean;
language: string;
timezone: string;
}Both the React web app and React Native mobile app import from the same package:
import type { User, UserPreferences } from '@project/shared';This eliminates type drift between platforms — a change to the User interface immediately shows type errors everywhere it's used.
API Client Generation
We auto-generate API clients from our FastAPI OpenAPI schema:
# Generate TypeScript client from FastAPI OpenAPI spec
openapi-generator-cli generate \
-i http://localhost:8000/openapi.json \
-g typescript-fetch \
-o packages/api-client/src \
--additional-properties=supportsES6=trueDocker Orchestration
Every service runs in Docker, orchestrated by docker-compose:
version: '3.8'
services:
api:
build: ./apps/api
ports: ["8000:8000"]
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/app
depends_on: [db, redis]
web:
build: ./apps/web
ports: ["3000:3000"]
depends_on: [api]
db:
image: postgres:16-alpine
volumes: ["pgdata:/var/lib/postgresql/data"]
redis:
image: redis:7-alpine
ports: ["6379:6379"]
volumes:
pgdata:CI/CD Pipeline
Our GitHub Actions pipeline:
Results
This architecture has allowed us to:
docker-compose up command