How the Celeris Web Monorepo Architecture Works with pnpm Workspaces

Celeris Web uses a single-repo monorepo powered by pnpm workspaces to link dozens of interdependent packages via workspace:* specifiers, centralize third-party versions through the catalog: protocol, and orchestrate builds across apps and services with a single pnpm-lock.yaml file.

The Celeris Web project (available at kirklin/celeris-web) organizes its frontend components, utilities, and applications into a scalable monorepo structure. By leveraging pnpm workspaces, the architecture eliminates dependency duplication while enabling atomic updates across shared libraries and consumer applications. This setup allows developers to run the admin UI, mock API, and shared packages simultaneously using a unified command interface.

Workspace Layout and Configuration

The foundation of the Celeris Web monorepo rests in the root pnpm-workspace.yaml file, which defines glob patterns for all workspace packages. This configuration tells pnpm which directories to treat as independent packages while maintaining them within a single dependency graph.


# pnpm-workspace.yaml

packages:
  - packages/shared/*
  - packages/web/*
  - packages/ai/**
  - apps/*
  - services/*
  - scripts

The workspace is divided into logical groups:

  • packages/shared/* – Common tooling, Vite plugins, and shared TypeScript configurations
  • packages/web/* – UI components, composables, directives, locale files, and request utilities
  • packages/ai/** – Future-proof placeholder for AI-related packages
  • apps/* – Full-stack applications such as the admin dashboard
  • services/* – Backend-like services including the mock admin API
  • scripts – Utility scripts such as the dependency tree generator

The root package.json marks the repository as private to prevent accidental publishing and pins the pnpm version for consistency:

{
  "private": true,
  "packageManager": "pnpm@10.10.0"
}

Dependency Management with workspace:* and Catalogs

Internal dependencies between workspace packages use the workspace:* version specifier. This protocol instructs pnpm to resolve the package from the local filesystem rather than the npm registry, ensuring that changes in shared code propagate immediately to dependent applications.

In packages/web/components/package.json (and similar packages), internal references follow this pattern:

"dependencies": {
  "@celeris/ca-components": "workspace:*",
  "@celeris/constants": "workspace:*",
  "@celeris/styles": "workspace:*",
  "@celeris/utils": "workspace:*"
}

For third-party dependencies, the architecture employs the catalog: protocol. Rather than scattering version numbers across individual package.json files, versions are centralized in the catalog: section of pnpm-workspace.yaml. This ensures that every package uses identical versions of Vue, Vite, Axios, and other shared libraries:

"devDependencies": {
  "vue": "catalog:",
  "vite": "catalog:"
}

pnpm creates hard-links from each package's node_modules to a central content-addressable store, eliminating duplicate installations of common dependencies across the monorepo.

Monorepo Scripts and Orchestration

The root package.json provides convenience scripts utilizing pnpm's --filter flag to target specific workspaces or run commands across multiple packages. These scripts abstract the complexity of working with multiple interdependent codebases.

Script Function Implementation Detail
pnpm bootstrap Installs all dependencies across the monorepo Equivalent to pnpm install at root
pnpm dev Launches both admin UI and mock API concurrently Uses run-p to execute filtered commands in parallel
pnpm dev:admin Starts the admin UI development server pnpm --filter @celeris/admin dev targeting apps/admin
pnpm dev:mock Starts the mock API service pnpm --filter @celeris/admin-api dev targeting services/admin-api
pnpm build Builds the admin UI for production pnpm --filter @celeris/admin build
pnpm clean Removes all node_modules and dist directories Ensures fresh install across entire workspace

When packages declare peerDependencies (such as Vue in @celeris/components), pnpm hoists compatible versions to the root node_modules directory, reducing disk usage and ensuring consistent runtime behavior across applications.

Development Workflow

Installing the Entire Monorepo

From the repository root, run:

pnpm bootstrap

# or simply:

pnpm i

pnpm reads the workspace configuration, resolves all workspace:* links to local paths, installs catalog-defined versions of third-party libraries, and generates a single pnpm-lock.yaml file at the root.

Running Development Servers

To start both the frontend application and its corresponding mock API simultaneously:

pnpm dev

This command executes pnpm --filter @celeris/admin dev (launching the Vite dev server for the admin UI) alongside pnpm --filter @celeris/admin-api dev (starting the mock service). Both processes share the same source tree, enabling hot-reload when modifying shared packages like @celeris/utils or @celeris/styles.

Importing Workspace Packages

Any package within the monorepo can import from siblings using standard module resolution:

// Inside apps/admin or packages/web/components
import { formatDate } from '@celeris/utils'
import { Button } from '@celeris/components'

TypeScript resolves these imports through the monorepo's unified node_modules structure without requiring additional path mapping configuration, as the workspace:* protocol ensures proper linking during installation.

Adding a New Package

To extend the monorepo with new functionality:

  1. Create a directory matching one of the glob patterns in pnpm-workspace.yaml (e.g., packages/web/new-feature)
  2. Add a package.json with "name": "@celeris/new-feature" and declare internal dependencies using "workspace:*"
  3. Run pnpm i to automatically register the new workspace and update the lockfile

Benefits of the pnpm Workspace Architecture

This architecture delivers several technical advantages for large-scale frontend development:

  • Zero-install duplication: Hard-linked content stores reduce disk usage by storing identical dependency versions once regardless of how many packages reference them.
  • Consistent versioning: The catalog: section centralizes third-party version management, while workspace:* guarantees internal packages remain synchronized without manual version bumping.
  • Deterministic CI/CD: A single lockfile ensures reproducible builds across development and production environments.
  • Scalable code sharing: Shared utilities (@celeris/utils), UI component libraries (@celeris/components), and build tooling (@celeris/vite) can be consumed by any application without publishing to npm or managing complex relative imports.
  • Atomic upgrades: Updating a dependency version in the catalog or modifying a shared utility immediately propagates to all dependents after a single install command.

Summary

  • The Celeris Web monorepo is defined by pnpm-workspace.yaml, which groups packages into apps/, packages/, services/, and scripts/ directories.
  • Internal dependencies use the workspace:* protocol to link local packages, while the catalog: protocol centralizes third-party version management.
  • Root scripts utilize pnpm --filter to run commands against specific workspaces, enabling commands like pnpm dev to orchestrate multiple services simultaneously.
  • pnpm's content-addressable store eliminates duplicate dependencies through hard-linking, significantly reducing disk usage compared to traditional node_modules structures.
  • The architecture supports hot-reloading across package boundaries, allowing changes in shared libraries to immediately reflect in consuming applications without rebuilds or republishing.

Frequently Asked Questions

What is the purpose of the workspace:* prefix in package.json files?

The workspace:* prefix tells pnpm to resolve the dependency from the local monorepo rather than fetching it from the npm registry. In Celeris Web, this ensures that when @celeris/components imports from @celeris/utils, it always uses the current source code from the repository rather than a potentially outdated published version, enabling real-time development across package boundaries.

How does the catalog: protocol manage dependency versions?

The catalog: protocol references versions defined in the catalog: section of the root pnpm-workspace.yaml file. Instead of specifying "vue": "^3.4.0" in every package that requires Vue, developers write "vue": "catalog:", and pnpm substitutes the version defined centrally. This guarantees that all packages use identical versions of shared frameworks and libraries, preventing version drift and conflicting peer dependencies.

How do I add a new package to the Celeris Web monorepo?

Create a new directory under one of the glob patterns defined in pnpm-workspace.yaml (such as packages/web/new-tool/), add a package.json with a scoped name like "@celeris/new-tool", and declare any internal dependencies using "workspace:*". Running pnpm i from the root automatically detects the new workspace, links it into the monorepo's dependency graph, and makes it available for filtering via pnpm --filter @celeris/new-tool.

What is the difference between apps/* and packages/* in this architecture?

The apps/* directory (such as apps/admin) contains deployable applications with entry points, build configurations, and environment-specific code. The packages/* directory contains library code—reusable components, utilities, and tooling—that multiple applications import. While both are valid workspaces, applications typically depend on many packages, whereas packages should remain agnostic of specific application implementations to maintain proper separation of concerns.

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 →