VibeFast
01 introduction

Monorepo Architecture

Understanding the monorepo structure, build orchestration, and development workflow.

The VibeFast project uses a modern monorepo architecture powered by Turborepo and PNPM. Practically, this just means you open one repo and get the mobile app, the web app, and the backend in one place.

Why a Monorepo?

A monorepo architecture provides several key benefits for mobile app development:

  • Shared Code: Common packages (UI components, utilities) can be shared across applications
  • Atomic Commits: Changes to multiple packages can be committed together
  • Efficient Development: Single command to work with all parts of the project
  • Consistent Dependencies: Centralized dependency management avoids version conflicts
  • Scalability: Easy to add new applications (web, admin panel, etc.) to share existing packages

Core Architecture Components

Turborepo: Build Orchestration

Turborepo is the backbone of our monorepo, providing intelligent caching and task orchestration.

{
  "$schema": "https://turbo.build/schema.json",
  "ui": "tui",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**", "**/*.d.ts"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

Key Features:

  • Caching: Intelligent caching of build outputs to speed up subsequent builds
  • Task Dependencies: Automatic handling of inter-package dependencies
  • Parallel Execution: Multiple tasks run in parallel when possible
  • Selective Builds: Build only packages that changed

PNPM Workspaces: Package Management

PNPM provides efficient package management with workspace support:

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

Benefits:

  • Disk Efficiency: Shared dependencies stored once
  • Fast Installation: Faster than npm/yarn for monorepos
  • Strict Dependencies: Prevents phantom dependencies

Workspace Structure

Applications (apps/)

Applications are runnable entry points for each platform.

apps/
├── native/                 # Expo + React Native mobile app (iOS & Android)
│   ├── src/                # Platform-specific source code
│   ├── assets/             # Shared mobile assets and fonts
│   ├── app.config.ts       # Expo configuration (and EAS presets)
│   └── package.json        # Mobile-only dependencies
├── web/                    # Next.js web app (marketing, docs, admin, etc.)
│   ├── app/                # File-based routes powering the web experience
│   ├── public/             # Static web assets
│   └── package.json        # Web-only dependencies and scripts
└── integrations/           # Experimental or partner integrations (optional)

Packages (packages/)

Packages are reusable code that can be shared across applications.

packages/
├── backend/               # @vibefast/backend
│   ├── convex/ or supabase/  # Backend code (depends on your choice)
│   ├── index.ts          # Package exports
│   └── package.json      # Backend dependencies
└── ui/                   # Shared UI components
    ├── components/       # Reusable components
    ├── index.ts          # Package exports
    └── package.json      # UI dependencies

Root Configuration

The root contains shared configuration and workspace-level tools:

.                          # Root directory
├── turbo.json            # Turborepo configuration
├── pnpm-workspace.yaml   # PNPM workspace configuration
├── package.json          # Workspace scripts and dev dependencies
├── eslint.config.mjs     # Shared linting configuration
└── tsconfig.json         # Shared TypeScript configuration

Development Workflow

Running Applications

# Start all applications in development mode
pnpm dev

# Start only the native app
pnpm dev:native

# Start only the backend
pnpm dev:server

# Start with specific environment
APP_ENV=staging pnpm dev:native

Building Applications

# Build all applications
pnpm build

# Build specific application
pnpm build:native

# Build backend package
pnpm build:backend

Testing

# Run tests for all packages
pnpm test

# Run tests for specific package
pnpm --filter native test

# Run E2E tests
pnpm native:e2e-test

# Type checking
pnpm check-types

# Linting
pnpm lint

Package Management

Adding Dependencies

Dependencies are added to specific packages or workspace-wide:

# Add to specific package
pnpm --filter native add react-native-some-lib

# Add to all packages
pnpm add -W typescript@latest

# Add dev dependency to workspace
pnpm add -D -W @types/node

Internal Dependencies

Packages can depend on each other using workspace references:

// apps/native/package.json
{
  "dependencies": {
    "@vibefast/backend": "workspace:*",
    "ui": "workspace:*"
  }
}

Environment Management

The monorepo supports multiple environments with specific configurations:

Environment Files

# Environment-specific configurations
.env.local                 # Local development
.env.staging              # Staging environment
.env.production           # Production environment

Environment Variables

Key environment variables are used across the workspace:

# App environment
APP_ENV=local|staging|production

# Backend URLs
CONVEX_SITE_URL=http://localhost:3001
CONVEX_DEPLOYMENT=...

# API keys
OPENAI_API_KEY=...
GOOGLE_GENERATIVE_AI_API_KEY=...

Build Orchestration

Task Pipeline

Turborepo orchestrates tasks based on dependencies:

1. Install dependencies (pnpm install)
2. Build shared packages (ui, backend)
3. Build applications (native)
4. Run tests (if needed)

Caching Strategy

  • Build Outputs: Cached in .turbo directory
  • Dependencies: Cached based on package.json changes
  • Environment Variables: Considered in cache keys when specified
  • Source Changes: Triggers selective rebuilds

Publishing and Deployment

Application Deployment

Each application can be deployed independently:

# Deploy native app
pnpm native:build:production

# Deploy with specific profile
pnpm native:build:staging

Package Publishing

Packages can be published to npm registries:

# Build package
pnpm --filter backend build

# Publish package
pnpm --filter backend publish

Best Practices

1. Package Boundaries

  • Keep packages focused on single responsibilities
  • Minimize cross-package dependencies
  • Use explicit exports rather than deep imports

2. Development Efficiency

  • Use pnpm dev for full-stack development
  • Leverage Turborepo caching for faster builds
  • Run pnpm check-types before committing

3. Code Organization

  • Group related features within packages
  • Use barrel exports (index.ts) for clean imports
  • Follow consistent naming conventions

4. Testing Strategy

  • Unit tests in individual packages
  • Integration tests across packages
  • E2E tests for complete applications

Troubleshooting

Common Issues

Dependency Conflicts:

# Clear all caches and reinstall
rm -rf node_modules .turbo
pnpm install

Build Cache Issues:

# Clear Turborepo cache
pnpm turbo clean

Workspace Resolution:

# Verify workspace setup
pnpm ls --depth=0

Environment Variables:

# Check current environment
echo $APP_ENV
# List environment files
ls -la .env*

This monorepo architecture provides a solid foundation for scaling your mobile application development while maintaining code quality and development efficiency.

Found an issue or bug in the docs?

Help me improve! If you spot any errors, typos, or have suggestions, please let me know.

Reach out on X/Twitter @zafarbuildzz

On this page