Setting Up Turborepo Build and Watch Workflow for Pascal Editor: Complete Monorepo Guide

Running bun dev triggers a persistent Turborepo watch pipeline that rebuilds @pascal-app/core and @pascal-app/viewer on every file change and hot‑reloads the Next.js 16 editor without cached artifacts.

Pascal Editor is organized as a Turborepo monorepo that orchestrates three interconnected packages—a Zustand‑backed core, a React Three Fiber viewer, and a Next.js 16 editor—to enable real‑time geometry editing with instantaneous feedback during development. This guide walks through the exact turbo.json configuration, workspace dependencies, and watch‑mode mechanics that make the repository’s build pipeline efficient and developer‑friendly.

Understanding the Monorepo Architecture

The repository splits functionality across three distinct workspaces defined in the root package.json:

Package Path Purpose
@pascal-app/core packages/core/ Schemas, Zustand scene store (useScene), geometry‑generation systems, and spatial queries (no UI)
@pascal-app/viewer packages/viewer/ 3‑D rendering components built on React Three Fiber, camera controllers, lights, and post‑processing
apps/editor apps/editor/ Next.js 16 application that composes the viewer, UI panels, tools, and editor‑only systems

Each package lists its siblings as workspace dependencies ("workspace:*"), ensuring that local changes propagate instantly without manual npm link operations.

How Turbo Orchestrates Development

The top‑level turbo.json defines task pipelines that enforce build order and enable persistent watch mode. The dev task configuration is the heart of the workflow:

{
  "dev": {
    "dependsOn": ["^build"],
    "cache": false,
    "persistent": true
  }
}
  • dependsOn: ["^build"] – Forces Turbo to compile every dependency (@pascal-app/core and @pascal-app/viewer) before starting the Next.js dev server.
  • cache: false – Disables Turborepo’s artifact cache during development so you always see the freshest JavaScript/TypeScript output.
  • persistent: true – Keeps the process alive, enabling hot‑reload for the editor when any source file changes.

When you execute bun dev, Turbo first runs ^build across the monorepo, then enters a file‑watcher that recompiles affected packages and signals the Next.js server to refresh.

One‑Command Quick Start

Install dependencies and start the watch workflow with a single terminal command:

bun install && bun dev

This sequence:

  1. Installs all packages using Bun’s workspace‑aware resolver.
  2. Builds @pascal-app/core and @pascal-app/viewer to their respective dist/ directories.
  3. Launches the Next.js development server on http://localhost:3000.
  4. Enters persistent watch mode, listening for changes in packages/core/src/, packages/viewer/src/, or apps/editor/.

Under‑the‑Hood Build Pipeline

Understanding the three‑stage pipeline helps debug build issues or optimize hot‑reload times.

Stage 1: Core and Viewer Compilation

When you modify packages/core/src/store/use-scene.ts or any file in the viewer, Turbo re‑executes the package’s build script (defined in package.json). The output lands in packages/core/dist/ and packages/viewer/dist/, which the Next.js app consumes via workspace link: references.

Stage 2: Next.js Dev Server

The apps/editor package starts its Next.js 16 server only after ^build succeeds. Because the core and viewer are workspace dependencies, Node resolves them directly from dist/ without publishing to npm.

Stage 3: Hot Reload Propagation

When useScene emits a dirty‑node flag (via markDirty), the viewer’s renderers detect the updated Zustand state and trigger a React re‑render. Meanwhile, Turbo’s watch process detects file‑system changes, recompiles the changed package, and the Next.js dev server refreshes the client automatically.

Adding New Core Systems: A Practical Example

Extend @pascal-app/core with a custom FloorSystem that regenerates plane geometry when nodes are marked dirty. Create packages/core/src/systems/floor-system.ts:

import { useFrame } from '@react-three/fiber'
import { useScene } from '../store/use-scene'
import { useRegistry } from '../hooks/use-registry'
import * as THREE from 'three'

export function FloorSystem() {
  const { nodes, markDirty } = useScene()
  const registry = useRegistry()

  useFrame(() => {
    for (const id of nodes.dirtyNodes) {
      const node = nodes[id]
      if (node.type !== 'floor') continue

      const obj = registry.get(id)
      if (!obj) continue

      obj.geometry?.dispose()
      obj.geometry = new THREE.PlaneGeometry(node.width, node.depth)

      markDirty(id)
    }
  })
}

Save the file. Turbo immediately rebuilds @pascal-app/core, the viewer picks up the new system export from packages/viewer/src/index.ts, and the running editor at localhost:3000 reflects the changes without a manual restart.

Running Individual Tasks

For scenarios where you need granular control, invoke these standard Turbo tasks:

  • bun run build – Runs turbo run build, ensuring ^build dependencies execute first for all packages.
  • bun run lint – Executes Biome linting across every workspace.
  • bun run check-types – Runs turbo run check-types to verify TypeScript integrity in packages/core/src/store/use-scene.ts and other entry points.
  • bun run kill – Terminates any stray process listening on port 3002 (used by Turborepo’s cache server).

Summary

  • Pascal Editor relies on a three‑package Turborepo architecture (core, viewer, editor) managed via turbo.json pipelines.
  • The dev task combines ^build dependencies, cache: false, and persistent: true to provide zero‑lag hot reload during geometry editing.
  • Workspace link: references let the Next.js app consume dist/ output instantly, eliminating the need for manual package publishing during development.
  • Bun serves as the package manager and task runner; bun dev is the only command required to bootstrap the watch workflow.
  • Changes to systems like FloorSystem propagate automatically through the Zustand store (useScene) and trigger React Three Fiber re‑renders without server restarts.

Frequently Asked Questions

What triggers a rebuild in the Pascal Editor watch mode?

Turbo’s file watcher monitors packages/core/src/, packages/viewer/src/, and apps/editor/ for TypeScript and asset changes. When you save a file—such as packages/core/src/store/use-scene.ts—Turbo invalidates the build graph for that package, recompiles to dist/, and signals the Next.js dev server to hot‑reload the client.

Why does the Turborepo dev task disable caching?

The dev task sets cache: false in turbo.json to ensure that every code change immediately produces fresh artifacts in dist/. Cached builds would risk serving stale JavaScript during active development of geometry systems or UI components, breaking the hot‑reload contract.

How do I integrate a new npm package into the build pipeline?

Add the dependency to the specific workspace’s package.json (e.g., apps/editor/package.json for UI libraries or packages/core/package.json for math utilities), run bun install from the root, and reference the new module in your code. Turbo automatically includes the new dependency graph in subsequent bun run build or bun dev executions without manual configuration changes.

Which port does the Next.js editor run on, and how do I stop conflicting processes?

The Next.js development server launches on port 3000. If Turborepo’s internal cache server or a zombie Node process blocks port 3002, execute bun run kill from the repository root; this script terminates any process listening on that port, allowing bun dev to start cleanly.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →