Professional Full-Stack Monorepo Guide: Next.js, Astro & Modern Tools

Complete architectural blueprint for building high-performance, type-safe full-stack monorepos with Next.js, Astro, Hono, Drizzle, and Turborepo in 2025.

Neuraldom Research Team

Author

Modern monorepo development setup with multiple frameworks and tools

5 min read

The Professional’s Guide to Building a Full-Stack Monorepo (2025 Edition)

Next.js | Astro | Hono | Drizzle | Turso | Bun | Turborepo

πŸ“‹ Overview

This guide provides a complete architectural blueprint for building a high-performance, type-safe, full-stack monorepo. It leverages the speed of Bun and Turborepo, the flexibility of a multi-app setup (Next.js, Astro, Hono), and a modern, edge-focused data layer with Drizzle and Turso. This is the definitive manual for a professional, scalable, and delightful developer experience.

πŸ’‘ Core Philosophy

  1. Type-Safety First: Shared types via Zod and TypeScript are the backbone of the project, ensuring data consistency from the database to the UI.
  2. Maximized Code Reuse: Logic, UI components, and configurations are defined once in packages/ and consumed everywhere.
  3. Automated Quality Gates: Local CI/CD with Lefthook ensures that no poorly formatted or failing code ever gets committed.
  4. Optimized for the Edge: The stack is chosen for performance, with applications and databases running close to the user.

πŸ› οΈ The Tech Stack: A Curated Selection

CategoryTechnologyRole & Rationale
ToolkitBunThe all-in-one foundation: package manager, runtime, and bundler. Chosen for its unmatched speed and simplicity.
MonorepoTurborepoThe high-performance build orchestrator. Manages the task pipeline, enabling intelligent caching and parallel execution.
Web AppNext.js 15.4+ (App Router)The primary, dynamic user-facing application. Chosen for its robust features and React ecosystem.
Content SiteAstro v5.12+The content-heavy site (blog, marketing pages). Chosen for its superior performance and content-first architecture.
APIHonoThe API server. Deployed on Cloudflare Workers for a lightweight, fast, and globally distributed backend.
UI ComponentsShadcn/UI & Tailwind CSSA pragmatic and beautiful component library built on top of the industry-standard utility-first CSS framework.
State (Next)ZustandA minimal, fast, and scalable state management solution for the React-heavy Next.js application.
State (Astro)NanostoresA tiny, framework-agnostic state manager, perfect for sharing state between UI islands in Astro.
ORM & SchemaDrizzle ORM & ZodA lightweight, type-safe SQL ORM. Paired with Zod for parsing and validating data from the database to the API.
DatabaseTursoA distributed SQLite database built on libSQL. Provides a fast, globally replicated database at the edge.
CachingRedis (e.g., Upstash)For high-speed caching, session storage, and rate limiting.
AuthenticationBetterAuthA modern, flexible authentication library that integrates well with the chosen stack.
Local CI/CDLefthookA language-agnostic, fast Git hooks manager. Enforces code quality before code is ever committed.

πŸ—οΈ Project Structure: The Blueprint

my-fullstack-monorepo/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ web/                     # Next.js 15 App
β”‚   β”œβ”€β”€ blog/                    # Astro App
β”‚   └── api/                     # Hono API for Cloudflare
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ ui/                      # Shared Shadcn/UI Components
β”‚   β”œβ”€β”€ db/                      # Drizzle ORM schema, client, and migrations
β”‚   β”œβ”€β”€ auth/                    # BetterAuth configuration and shared logic
β”‚   β”œβ”€β”€ store/                   # Zustand and Nanostores state management
β”‚   β”œβ”€β”€ types/                   # Shared Zod schemas and TypeScript types
β”‚   β”œβ”€β”€ eslint-config/           # Shared ESLint configuration
β”‚   └── typescript-config/       # Shared tsconfig.json files
β”œβ”€β”€ .gitignore
β”œβ”€β”€ lefthook.yml                 # Lefthook Git hooks configuration
β”œβ”€β”€ package.json                 # The root package configuration
β”œβ”€β”€ bun.lockb                    # Bun's lockfile
└── turbo.json                   # Turborepo pipeline configuration

πŸš€ Step 1: Initialization and Setup

  1. Create the Turborepo project with Bun:

    bunx create-turbo@latest my-fullstack-monorepo
  2. Clean up and rename default apps:

    • Rename apps/web to apps/web-main or your desired name.
    • Delete apps/docs.
  3. Add the Astro and Hono apps:

    # Navigate to the apps directory
    cd my-fullstack-monorepo/apps
    
    # Scaffold the Astro blog
    bun create astro@latest blog
    
    # Scaffold the Hono API
    bun create hono@latest api

    Follow the prompts, but do not initialize a new git repository.

  4. Adapt and Integrate:

    • For both blog and api, modify their package.json and tsconfig.json files to use the shared workspace configurations (@repo/typescript-config, @repo/eslint-config), as detailed in the previous answers.
  5. Install all dependencies from the root:

    # Navigate back to the root directory
    cd ..
    bun install

πŸ”§ Step 2: Configuration Deep Dive

turbo.json - The Build Pipeline

Define all tasks, ensuring database generation happens before builds.

{
  "$schema": "https://turborepo.com/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build", "db:generate"],
      "outputs": [".next/**", "dist/**", ".astro/**"]
    },
    "db:generate": {
      "cache": "false"
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {},
    "check-types": {
      "dependsOn": ["^build"]
    }
  }
}

packages/db - The Data Layer

  • package.json:
    {
      "name": "@repo/db",
      "main": "./src/index.ts",
      "scripts": {
        "db:generate": "drizzle-kit generate",
        "db:migrate": "drizzle-kit migrate"
      },
      "dependencies": {
        "drizzle-orm": "latest",
        "@libsql/client": "latest"
      },
      "devDependencies": {
        "drizzle-kit": "latest"
      }
    }
  • drizzle.config.ts:
    import type { Config } from "drizzle-kit";
    
    export default {
      schema: "./src/schema.ts",
      driver: "turso",
      dbCredentials: {
        url: process.env.TURSO_DATABASE_URL!,
        authToken: process.env.TURSO_AUTH_TOKEN!,
      },
    } satisfies Config;
  • src/index.ts: Exports the Drizzle client instance.
  • src/schema.ts: Defines your database tables.

packages/ui - The UI System with Shadcn/UI

This is the standard way to make Shadcn/UI work in a monorepo.

  1. Setup tailwind.config.ts in this package:
    // packages/ui/tailwind.config.ts
    import type { Config } from "tailwindcss";
    
    // A shared config that can be imported by apps
    const config: Config = {
      darkMode: ["class"],
      content: ["./src/**/*.{ts,tsx}"], // Only scans components within this package
      // ... rest of shadcn/ui config
    };
    export default config;
  2. Apps extend this config:
    // apps/web/tailwind.config.ts
    import type { Config } from "tailwindcss";
    import sharedConfig from "@repo/ui/tailwind.config";
    
    const config: Pick<Config, "presets"> = {
      presets: [sharedConfig],
    };
    export default config;

packages/store - The State Layer

  • src/zustand.ts: Exports Zustand stores for the Next.js app.
  • src/nanostores.ts: Exports Nanostores atoms for the Astro app.

βœ… Step 3: Local CI/CD with Lefthook

Enforce quality at the commit level.

  1. Install Lefthook:

    brew install lefthook # or use another method
    bun add -D lefthook
  2. Create lefthook.yml in the root:

    pre-commit:
      parallel: true
      commands:
        linter:
          glob: "*.{ts,tsx,astro}"
          run: bun run lint --fix {staged_files}
        formatter:
          glob: "*.{js,ts,tsx,md,json,astro}"
          run: bun prettier --write {staged_files}
    
    pre-push:
      commands:
        type-check:
          run: bun run check-types
        tests:
          run: bun run test
  3. Activate Lefthook:

    lefthook install

    Now, every git commit will automatically lint and format your staged files.


πŸ’» Step 4: The Development Workflow

  • Start all services:
    bun run dev
  • Work on a specific app:
    bun run dev --filter=web
  • Generate database migrations:
    bun run db:generate
  • Commit your changes:
    git add .
    git commit -m "feat: add user profile page" 
    # Lefthook runs automatically, ensuring quality.

πŸš€ Step 5: Deployment

  • Next.js App (web): Deploy to Vercel. Connect your Git repository, and Vercel will automatically detect the Turborepo setup and build only what’s necessary.
  • Astro App (blog): Deploy to Cloudflare Pages. Point it to the apps/blog directory and set the build command to bun run build.
  • Hono API (api): Deploy to Cloudflare Workers. Use wrangler deploy from within the apps/api directory or via a root script.
  • Environment Variables: Configure TURSO_DATABASE_URL, REDIS_URL, etc., in your hosting providers’ settings.

This comprehensive structure provides a scalable, maintainable, and highly performant foundation for any modern full-stack project.