monorepo-generator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Monorepo Generator

Monorepo 生成器

Generate scalable monorepo structures for full-stack applications with shared packages.
为带有共享包的全栈应用生成可扩展的Monorepo结构。

Quick Start

快速开始

bash
mkdir my-monorepo && cd my-monorepo
bun init -y  # or: pnpm init / npm init -y

bash
mkdir my-monorepo && cd my-monorepo
bun init -y  # or: pnpm init / npm init -y

Workflow

工作流程

Step 1: Gather Requirements

步骤1:收集需求

Ask user what project types they need:
TypeExamplesCommon Stack
FrontendWeb app, admin dashboard, docs siteNext.js 15, React 19, Tailwind
APIREST API, GraphQL serverHono, Express, Fastify
PipelineETL jobs, cron tasks, workersNode scripts, Python
CLIDeveloper tools, automationCommander, Yargs
MobileReact Native appExpo, React Native
询问用户需要的项目类型:
类型示例常用技术栈
前端Web应用、管理后台、文档站点Next.js 15, React 19, Tailwind
APIREST API、GraphQL服务器Hono, Express, Fastify
数据管道ETL任务、定时任务、工作器Node脚本、Python
CLI开发者工具、自动化工具Commander, Yargs
移动应用React Native应用Expo, React Native

Step 2: Choose Package Manager

步骤2:选择包管理器

  • Bun (recommended): Fastest, built-in workspaces
  • PNPM: Efficient disk usage, strict dependencies
  • Yarn: Mature ecosystem, plug'n'play option
See Package Manager Guide for configs.
  • Bun(推荐):速度最快,内置工作区支持
  • PNPM:磁盘使用高效,依赖管理严格
  • Yarn:生态成熟,支持即插即用选项
查看包管理器指南获取配置信息。

Step 3: Create Directory Structure

步骤3:创建目录结构

/monorepo/
├── apps/                       # Deployable applications
│   ├── web/                    # Next.js frontend
│   ├── api/                    # Hono/Express API
│   ├── admin/                  # Admin dashboard
│   └── docs/                   # Documentation site
├── services/                   # Backend services & workers
│   ├── jobs/                   # Scheduled jobs/cron
│   ├── workers/                # Background workers
│   └── pipelines/              # Data pipelines
├── packages/                   # Shared libraries
│   ├── ui/                     # React components (shadcn/ui)
│   ├── utils/                  # Shared utilities
│   ├── db/                     # Database client & schemas
│   ├── api-client/             # Generated API client
│   ├── config/                 # Shared configuration
│   ├── eslint-config/          # Shared ESLint
│   └── typescript-config/      # Shared TS configs
├── package.json                # Workspace root
├── turbo.json                  # Turborepo config
└── .gitignore
Adapt structure based on needs—not all projects need all directories.
/monorepo/
├── apps/                       # 可部署应用
│   ├── web/                    # Next.js前端
│   ├── api/                    # Hono/Express API
│   ├── admin/                  # 管理后台
│   └── docs/                   # 文档站点
├── services/                   # 后端服务与工作器
│   ├── jobs/                   # 定时任务/Cron
│   ├── workers/                # 后台工作器
│   └── pipelines/              # 数据管道
├── packages/                   # 共享库
│   ├── ui/                     # React组件(shadcn/ui)
│   ├── utils/                  # 共享工具函数
│   ├── db/                     # 数据库客户端与Schema
│   ├── api-client/             # 生成的API客户端
│   ├── config/                 # 共享配置
│   ├── eslint-config/          # 共享ESLint配置
│   └── typescript-config/      # 共享TypeScript配置
├── package.json                # 工作区根目录配置
├── turbo.json                  # Turborepo配置
└── .gitignore
根据需求调整结构——并非所有项目都需要所有目录。

Step 4: Create Root Configuration

步骤4:创建根目录配置

Root package.json:
json
{
  "name": "monorepo",
  "private": true,
  "workspaces": ["apps/*", "services/*", "packages/*"],
  "scripts": {
    "dev": "turbo dev",
    "build": "turbo build",
    "lint": "turbo lint",
    "type-check": "turbo type-check",
    "test": "turbo test"
  },
  "devDependencies": {
    "turbo": "^2.3.0",
    "typescript": "^5.7.0"
  },
  "packageManager": "bun@1.1.0"
}
turbo.json:
json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": { "cache": false, "persistent": true },
    "start": { "dependsOn": ["build"] },
    "lint": { "dependsOn": ["^lint"] },
    "type-check": { "dependsOn": ["^type-check"] },
    "test": { "dependsOn": ["^build"] }
  }
}

根目录package.json:
json
{
  "name": "monorepo",
  "private": true,
  "workspaces": ["apps/*", "services/*", "packages/*"],
  "scripts": {
    "dev": "turbo dev",
    "build": "turbo build",
    "lint": "turbo lint",
    "type-check": "turbo type-check",
    "test": "turbo test"
  },
  "devDependencies": {
    "turbo": "^2.3.0",
    "typescript": "^5.7.0"
  },
  "packageManager": "bun@1.1.0"
}
turbo.json:
json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": { "cache": false, "persistent": true },
    "start": { "dependsOn": ["build"] },
    "lint": { "dependsOn": ["^lint"] },
    "type-check": { "dependsOn": ["^type-check"] },
    "test": { "dependsOn": ["^build"] }
  }
}

Project Templates

项目模板

Frontend App (Next.js)

前端应用(Next.js)

json
// apps/web/package.json
{
  "name": "web",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/ui": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "next": "^15.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "tailwindcss": "^4.0.0",
    "typescript": "^5.7.0"
  }
}
typescript
// apps/web/next.config.ts
import type { NextConfig } from 'next';

const config: NextConfig = {
  transpilePackages: ['@monorepo/ui', '@monorepo/utils'],
};

export default config;
json
// apps/web/package.json
{
  "name": "web",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/ui": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "next": "^15.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "tailwindcss": "^4.0.0",
    "typescript": "^5.7.0"
  }
}
typescript
// apps/web/next.config.ts
import type { NextConfig } from 'next';

const config: NextConfig = {
  transpilePackages: ['@monorepo/ui', '@monorepo/utils'],
};

export default config;

API Server (Hono)

API服务器(Hono)

json
// apps/api/package.json
{
  "name": "api",
  "private": true,
  "scripts": {
    "dev": "bun run --hot src/index.ts",
    "build": "bun build src/index.ts --outdir dist --target node",
    "start": "bun run dist/index.js",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/db": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "hono": "^4.6.0",
    "@hono/node-server": "^1.13.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "@types/node": "^22.0.0",
    "typescript": "^5.7.0"
  }
}
typescript
// apps/api/src/index.ts
import { serve } from '@hono/node-server';
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';

const app = new Hono();

app.use('*', logger());
app.use('*', cors());

app.get('/', (c) => c.json({ status: 'ok' }));
app.get('/health', (c) => c.json({ healthy: true }));

// Routes
app.route('/api/users', usersRouter);
app.route('/api/items', itemsRouter);

serve({ fetch: app.fetch, port: 3001 }, (info) => {
  console.log(`API running on http://localhost:${info.port}`);
});
json
// apps/api/package.json
{
  "name": "api",
  "private": true,
  "scripts": {
    "dev": "bun run --hot src/index.ts",
    "build": "bun build src/index.ts --outdir dist --target node",
    "start": "bun run dist/index.js",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/db": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "hono": "^4.6.0",
    "@hono/node-server": "^1.13.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "@types/node": "^22.0.0",
    "typescript": "^5.7.0"
  }
}
typescript
// apps/api/src/index.ts
import { serve } from '@hono/node-server';
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';

const app = new Hono();

app.use('*', logger());
app.use('*', cors());

app.get('/', (c) => c.json({ status: 'ok' }));
app.get('/health', (c) => c.json({ healthy: true }));

// Routes
app.route('/api/users', usersRouter);
app.route('/api/items', itemsRouter);

serve({ fetch: app.fetch, port: 3001 }, (info) => {
  console.log(`API running on http://localhost:${info.port}`);
});

Background Worker/Job

后台工作器/任务

json
// services/jobs/package.json
{
  "name": "jobs",
  "private": true,
  "scripts": {
    "dev": "bun run --watch src/index.ts",
    "build": "bun build src/index.ts --outdir dist --target node",
    "start": "bun run dist/index.js",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/db": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "cron": "^3.1.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "@types/cron": "^2.4.0",
    "typescript": "^5.7.0"
  }
}
typescript
// services/jobs/src/index.ts
import { CronJob } from 'cron';
import { db } from '@monorepo/db';

// Run every hour
const hourlyJob = new CronJob('0 * * * *', async () => {
  console.log('Running hourly job...');
  // Your job logic here
});

// Run daily at midnight
const dailyJob = new CronJob('0 0 * * *', async () => {
  console.log('Running daily cleanup...');
  // Cleanup logic here
});

hourlyJob.start();
dailyJob.start();

console.log('Job scheduler started');
json
// services/jobs/package.json
{
  "name": "jobs",
  "private": true,
  "scripts": {
    "dev": "bun run --watch src/index.ts",
    "build": "bun build src/index.ts --outdir dist --target node",
    "start": "bun run dist/index.js",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/db": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "cron": "^3.1.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "@types/cron": "^2.4.0",
    "typescript": "^5.7.0"
  }
}
typescript
// services/jobs/src/index.ts
import { CronJob } from 'cron';
import { db } from '@monorepo/db';

// Run every hour
const hourlyJob = new CronJob('0 * * * *', async () => {
  console.log('Running hourly job...');
  // Your job logic here
});

// Run daily at midnight
const dailyJob = new CronJob('0 0 * * *', async () => {
  console.log('Running daily cleanup...');
  // Cleanup logic here
});

hourlyJob.start();
dailyJob.start();

console.log('Job scheduler started');

Data Pipeline

数据管道

json
// services/pipelines/package.json
{
  "name": "pipelines",
  "private": true,
  "scripts": {
    "etl:users": "bun run src/etl/users.ts",
    "etl:analytics": "bun run src/etl/analytics.ts",
    "build": "bun build src/**/*.ts --outdir dist",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/db": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "zod": "^3.23.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "typescript": "^5.7.0"
  }
}
typescript
// services/pipelines/src/etl/users.ts
import { db } from '@monorepo/db';
import { z } from 'zod';

const UserSchema = z.object({
  id: z.string(),
  email: z.string().email(),
  createdAt: z.coerce.date(),
});

async function extractUsers() {
  // Extract from source
}

async function transformUsers(raw: unknown[]) {
  return raw.map((r) => UserSchema.parse(r));
}

async function loadUsers(users: z.infer<typeof UserSchema>[]) {
  // Load to destination
}

async function main() {
  console.log('Starting ETL pipeline...');
  const raw = await extractUsers();
  const transformed = await transformUsers(raw);
  await loadUsers(transformed);
  console.log(`Processed ${transformed.length} users`);
}

main().catch(console.error);

json
// services/pipelines/package.json
{
  "name": "pipelines",
  "private": true,
  "scripts": {
    "etl:users": "bun run src/etl/users.ts",
    "etl:analytics": "bun run src/etl/analytics.ts",
    "build": "bun build src/**/*.ts --outdir dist",
    "type-check": "tsc --noEmit"
  },
  "dependencies": {
    "@monorepo/db": "workspace:*",
    "@monorepo/utils": "workspace:*",
    "zod": "^3.23.0"
  },
  "devDependencies": {
    "@monorepo/typescript-config": "workspace:*",
    "typescript": "^5.7.0"
  }
}
typescript
// services/pipelines/src/etl/users.ts
import { db } from '@monorepo/db';
import { z } from 'zod';

const UserSchema = z.object({
  id: z.string(),
  email: z.string().email(),
  createdAt: z.coerce.date(),
});

async function extractUsers() {
  // Extract from source
}

async function transformUsers(raw: unknown[]) {
  return raw.map((r) => UserSchema.parse(r));
}

async function loadUsers(users: z.infer<typeof UserSchema>[]) {
  // Load to destination
}

async function main() {
  console.log('Starting ETL pipeline...');
  const raw = await extractUsers();
  const transformed = await transformUsers(raw);
  await loadUsers(transformed);
  console.log(`Processed ${transformed.length} users`);
}

main().catch(console.error);

Shared Packages

共享包

packages/utils

packages/utils

typescript
// packages/utils/src/index.ts
export { cn } from './cn';
export { formatDate, parseDate } from './date';
export { sleep, retry } from './async';
export type { Result, AsyncResult } from './types';
typescript
// packages/utils/src/index.ts
export { cn } from './cn';
export { formatDate, parseDate } from './date';
export { sleep, retry } from './async';
export type { Result, AsyncResult } from './types';

packages/db

packages/db

json
// packages/db/package.json
{
  "name": "@monorepo/db",
  "private": true,
  "exports": { ".": "./src/index.ts" },
  "dependencies": {
    "drizzle-orm": "^0.36.0",
    "postgres": "^3.4.0"
  },
  "devDependencies": {
    "drizzle-kit": "^0.28.0",
    "@monorepo/typescript-config": "workspace:*"
  }
}
json
// packages/db/package.json
{
  "name": "@monorepo/db",
  "private": true,
  "exports": { ".": "./src/index.ts" },
  "dependencies": {
    "drizzle-orm": "^0.36.0",
    "postgres": "^3.4.0"
  },
  "devDependencies": {
    "drizzle-kit": "^0.28.0",
    "@monorepo/typescript-config": "workspace:*"
  }
}

packages/config

packages/config

typescript
// packages/config/src/index.ts
import { z } from 'zod';

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  DATABASE_URL: z.string().url(),
  API_URL: z.string().url().optional(),
  LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});

export const config = envSchema.parse(process.env);
export type Config = z.infer<typeof envSchema>;

typescript
// packages/config/src/index.ts
import { z } from 'zod';

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  DATABASE_URL: z.string().url(),
  API_URL: z.string().url().optional(),
  LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});

export const config = envSchema.parse(process.env);
export type Config = z.infer<typeof envSchema>;

TypeScript Configs

TypeScript配置

json
// packages/typescript-config/base.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "declaration": true,
    "declarationMap": true
  }
}
json
// packages/typescript-config/node.json (for APIs/services)
{
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["ES2022"],
    "noEmit": true
  }
}
json
// packages/typescript-config/nextjs.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["DOM", "DOM.Iterable", "ES2022"],
    "jsx": "preserve",
    "noEmit": true,
    "plugins": [{ "name": "next" }]
  }
}

json
// packages/typescript-config/base.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "declaration": true,
    "declarationMap": true
  }
}
json
// packages/typescript-config/node.json (for APIs/services)
{
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["ES2022"],
    "noEmit": true
  }
}
json
// packages/typescript-config/nextjs.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["DOM", "DOM.Iterable", "ES2022"],
    "jsx": "preserve",
    "noEmit": true,
    "plugins": [{ "name": "next" }]
  }
}

Adding New Projects

添加新项目

bash
undefined
bash
undefined

New frontend

New frontend

mkdir -p apps/dashboard && cp -r apps/web/* apps/dashboard/
mkdir -p apps/dashboard && cp -r apps/web/* apps/dashboard/

New API

New API

mkdir -p apps/gateway && cp -r apps/api/* apps/gateway/
mkdir -p apps/gateway && cp -r apps/api/* apps/gateway/

New service

New service

mkdir -p services/notifications

Update `package.json` name and dependencies for each new project.

---
mkdir -p services/notifications

更新每个新项目的`package.json`名称和依赖。

---

Deployment

部署

Project TypeDeployment Options
FrontendVercel, Netlify, Cloudflare Pages
APIRailway, Fly.io, AWS Lambda, Docker
WorkersRailway, Render, AWS ECS
JobsCron service, GitHub Actions, Temporal
Each project deploys independently from its directory.

项目类型部署选项
前端Vercel, Netlify, Cloudflare Pages
APIRailway, Fly.io, AWS Lambda, Docker
工作器Railway, Render, AWS ECS
任务Cron服务, GitHub Actions, Temporal
每个项目独立从其目录部署。

Resources

资源

  • Package Manager Guide - Bun/PNPM/Yarn configs
  • assets/ - Template files for scaffolding
  • 包管理器指南 - Bun/PNPM/Yarn配置
  • assets/ - 用于脚手架的模板文件