Skip to main content

Monorepo Structure

SkyTeam ROBLOX uses a Turborepo-powered monorepo to manage multiple applications and shared packages efficiently.

Overview

The project is organized as a pnpm workspace with Turborepo for build orchestration. This structure enables:
  • Shared code between applications
  • Efficient caching and parallel builds
  • Simplified dependency management
  • Consistent tooling across all packages

Workspace Configuration

pnpm Workspace

The workspace is defined in pnpm-workspace.yaml:
packages:
    - "apps/*"
    - "packages/*"
This configuration tells pnpm to treat all directories under apps/ and packages/ as workspace members.

Turborepo Configuration

Turborepo is configured in turbo.json with the following key settings:
{
  "globalDependencies": [".env"],
  "globalEnv": [
    "DATABASE_URL",
    "DISCORD_TOKEN",
    "DISCORD_HOME_GUILD_ID",
    "DISCORD_CLIENT_ID",
    "NEXT_PUBLIC_API_URL",
    "ADMIN_JWT_SECRET"
  ],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    },
    "lint": {},
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
Key Features:
  • Global Dependencies: Changes to .env invalidate all caches
  • Global Environment Variables: Required env vars for builds
  • Task Pipeline: Build tasks run dependencies first (^build)
  • Output Caching: Caches build outputs for faster rebuilds
  • Dev Mode: Development servers run persistently without caching

Directory Structure

skyteam/
├── apps/                    # Application packages
│   ├── admin/              # Admin panel (Next.js)
│   ├── api/                # Backend API (Express)
│   ├── client/             # Discord bot (Discord.js + Discordx)
│   ├── models/             # ROBLOX MainModule (Rojo + roblox-ts)
│   └── web/                # Main website (Next.js)
├── packages/                # Shared packages
│   ├── database/           # Drizzle PostgreSQL client
│   └── ui/                 # Shared UI components
├── .env.example            # Environment variable template
├── package.json            # Root package with scripts
├── pnpm-workspace.yaml     # Workspace configuration
├── pnpm-lock.yaml          # Lockfile
└── turbo.json             # Turborepo configuration

Apps vs Packages

Apps

Applications are deployable, standalone services. Each app has its own runtime and serves a specific purpose:
  • Technology: Next.js 15
  • Port: 3000 (dev)
  • Purpose: Public-facing website for SkyTeam ROBLOX
  • Dependencies: @skyteam/database, @skyteam/ui
  • Technology: Next.js
  • Port: 3001 (dev)
  • Purpose: Administrative dashboard
  • Dependencies: @skyteam/ui
  • Technology: Express.js
  • Port: 4000 (dev)
  • Purpose: REST API for data operations
  • Dependencies: @skyteam/database
  • Scripts:
    • build: Bundles with tsup
    • dev: Watches and auto-restarts on changes
    • start: Runs production build
  • Technology: Discord.js + Discordx
  • Purpose: Discord integration and bot commands
  • Dependencies: @skyteam/database
  • Type: ESM module
  • Technology: Roblox-ts + Rojo
  • Purpose: ROBLOX game integration
  • Scripts:
    • build: Compiles TypeScript to Luau
    • dev:watch: Watches for TypeScript changes
    • dev:serve: Runs Rojo live sync server
    • dev: Runs both watch and serve concurrently

Packages

Packages are shared libraries consumed by apps. They export reusable code:
  • Purpose: PostgreSQL database client and schema
  • Technology: Drizzle ORM
  • Exports: Database client, schema, queries
  • Scripts:
    • db:generate: Generate migrations from schema
    • db:push: Push schema changes to database
    • db:studio: Launch Drizzle Studio (database GUI)
  • Consumed by: api, client, web
  • Purpose: Shared React components and styles
  • Technology: React + Tailwind CSS
  • Consumed by: web, admin

Workspace Dependencies

Packages reference each other using the workspace:* protocol:
{
  "dependencies": {
    "@skyteam/database": "workspace:*"
  }
}
This tells pnpm to:
  • Link to the local workspace package during development
  • Resolve to the exact version when publishing (not applicable for private monorepos)

Package Manager

The project requires pnpm 10.5.2 or later:
{
  "packageManager": "[email protected]",
  "engines": {
    "node": ">=18.0.0"
  }
}
pnpm creates symlinks between workspace packages, making development fast and efficient. Changes to a shared package are immediately available to consuming apps without rebuilding.

Dependency Graph

The database package is the most widely used shared dependency, consumed by the web app, API, and Discord client.

Build docs developers (and LLMs) love