Skip to main content
Monkeytype is built as a modern monorepo application with a clear separation between frontend, backend, and shared packages. The architecture prioritizes performance, type safety, and maintainability.

Monorepo Structure

The project uses a pnpm workspace managed by Turborepo for efficient builds and caching:

Build System

Monkeytype uses Turborepo to orchestrate builds across the monorepo:
turbo.json
Key features:
  • Dependency-aware builds: Packages build in correct order (^build dependency)
  • Incremental builds: Only rebuilds changed packages
  • Parallel execution: Independent tasks run concurrently
  • Smart caching: Turborepo caches build outputs

Package Scripts

The root package.json provides commands for the entire monorepo:

Technology Stack

Frontend Stack

Frontend source location: /frontend/src/ts/

Backend Stack

Backend source location: /backend/src/

Shared Packages

@monkeytype/contracts
  • Type-safe API contracts using @ts-rest/core
  • Shared between frontend and backend
  • Ensures API type safety at compile time
@monkeytype/schemas
  • Zod schemas for runtime validation
  • TypeScript types derived from schemas
  • Used for users, results, configs, etc.
@monkeytype/util
  • Shared utility functions
  • Date/time helpers, string manipulation
@monkeytype/funbox
  • Test mode and funbox definitions
  • Shared game logic

System Architecture Diagram

Request Flow

A typical request flows through the system as follows:
  1. Frontend: User action triggers API call via @ts-rest/core client
  2. Type Safety: Request matches contract definition from @monkeytype/contracts
  3. Backend: Express receives request at ts-rest endpoint
  4. Middleware Pipeline:
    • Context middleware attaches request metadata
    • Authentication verifies Firebase token or ApeKey
    • Rate limiter checks request limits
    • Validation ensures request schema matches contract
  5. Controller: Business logic processes the request
  6. DAL: Data access layer queries MongoDB or Redis
  7. Response: Type-safe response returned via contract

Authentication Flow

Key Design Principles

Type Safety

  • End-to-end types: Types flow from schemas → contracts → frontend
  • Runtime validation: Zod schemas validate at runtime
  • Compile-time checks: TypeScript catches errors before deployment

Performance

  • Redis caching: Frequent queries cached (leaderboards, configs)
  • Lazy loading: Frontend code-splits by route
  • Optimistic updates: UI updates before server confirmation
  • PWA support: Service worker for offline capability

Scalability

  • Horizontal scaling: Stateless backend servers
  • Database indexing: MongoDB indices on common queries
  • Queue system: BullMQ handles async jobs (emails, reports)
  • CDN delivery: Static assets served from CDN

Development Workflow

Local Development

Build Pipeline

Next Steps