My-WebPage pnpm-workspace
Understand and build on the pnpm monorepo template. Use when working on workspace structure, TypeScript project references, dependency management, artifact routing, shared libraries, or cross-package changes.
git clone https://github.com/MayankSaini-Byte/My-WebPage
T=$(mktemp -d) && git clone --depth=1 https://github.com/MayankSaini-Byte/My-WebPage "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.local/skills/pnpm-workspace" ~/.claude/skills/mayanksaini-byte-my-webpage-pnpm-workspace && rm -rf "$T"
.local/skills/pnpm-workspace/SKILL.mdpnpm workspace skill
Structure
artifacts-monorepo/ ├── artifacts/ # Deployable applications ├── lib/ # Shared libraries ├── scripts/ # Utility scripts (single workspace package) ├── pnpm-workspace.yaml # Workspace package discovery, catalog pins, overrides ├── tsconfig.base.json # Shared strict TS defaults for packages that can extend it ├── tsconfig.json # Root TS solution config for composite libs only └── package.json # Root task orchestration and shared dev tooling
TypeScript
Default model:
packages are composite and emit declarations vialib/*
.tsc --build
andartifacts/*
are leaf workspace packages checked withscripts
. They should never import from each other, if you need to share functionality (encouraged) you must create a new lib.tsc --noEmit- Root
is a solution file for libs only, used bytsconfig.json
.tsc --build
contains shared strict defaults. Not all packages extend it (e.g. Expo apps will use its own base).tsconfig.base.json
Root commands:
runspnpm run typecheck:libs
for the composite libs.tsc --build
is the canonical full check: builds libs first, then runs leaf workspace package typechecks.pnpm run typecheck- Prefer the root
result over editor/LSP state when they disagree.typecheck
Adding a new lib:
- Add
,composite
, anddeclarationMap
to itsemitDeclarationOnly
.tsconfig.json - Add it to the root
tsconfig.json
array.references - If it imports another lib, add that lib to its own
.references
Adding a new artifact:
- Should be usually handled via
unless no artifact template satisfies the user's requirements.create-artifact - Do not add it to the root
references.tsconfig.json
Project references:
- When one lib imports another lib, the importing lib must declare it in
soreferences
can order and rebuild correctly.tsc --build - Root
should list the lib packages, not every workspace package.tsconfig.json - Artifact
to libs are optional but useful for:references- explicit documentation of direct workspace dependencies
- better editor/tsserver project awareness
- standalone
style workflowstsc -b artifacts/<name>
Server & API contracts
For backend-backed apps, define the contract in OpenAPI first, then generate helpers from it.
Codegen command:
pnpm --filter @workspace/api-spec run codegen
This generates files such as React Query hooks and Zod schemas. It is strongly recommended that you use them. The server should use Zod schemas to validate inputs and outputs, and clients should use the available hooks.
References
— Setting up OpenAPI spec and code generation in this contract-first repo.references/openapi.md
— Important information about adding routes and general tips.references/server.md
— Adding new database schemas and running migrations.references/db.md
scripts
(@workspace/scripts
)
scripts@workspace/scriptsPut shared utility scripts in
./scripts.
- Each script lives in
scripts/src/ - Add a matching npm script in
scripts/package.json
is treated like a leaf workspace package and typechecked withscriptstsc --noEmit
Proxy & service routing
A global reverse proxy routes traffic by path using each artifact's
.replit-artifact/artifact.toml.
Example:
[[services]] localPort = 8080 name = "API Server" paths = ["/api"]
Rules for accessing services:
- For ad hoc requests, such as
, always go through the shared proxy atcurl
. Never call service ports directly.localhost:80- Correct:
localhost:80/api/healthz - Wrong:
localhost:8080/api/healthz
- Correct:
- Paths are not rewritten. Services must handle their full base path themselves.
- The only exception is the EXPO artifact. If one exists, use $REPLIT_EXPO_DEV_DOMAIN to access it locally.
- In application code, prefer relative URLs when possible. For user-facing access, both development previews and published production domains already route through the shared proxy automatically. Published apps are exposed over HTTPS on the domains listed in
(comma-separated).$REPLIT_DOMAINS - Do NOT add Vite proxy configs or custom base URLs to reach other services; the shared proxy already handles cross-service routing.
- Routes across artifacts are matched most-specific-first, so a service on
won't conflict with one on/api
./
Package management
Workspace package rules:
- Workspace package names should use the
prefix.@workspace/ - Each package must declare its own dependencies; dependencies are not shared implicitly across workspace packages.
- Root dependencies are for repo-level tooling such as
,typescript
,prettier
,eslint
, etc.vitest - Do not use
.pnpm add --no-frozen-lockfile
will automatically usepnpm add
if the dependency already has a catalog entry.catalog:
Dependency catalogs
pnpm-workspace.yaml uses catalog: entries to pin shared versions in one place.
Use the catalog when:
- a dependency is shared by a library and its consumers
- a dependency should stay aligned across multiple workspace packages
Rules:
- If a dependency already exists in the catalog, use
."catalog:" - If a lib and its consumers both use a dependency, prefer adding it to the catalog and updating all relevant packages together.
- Only hardcode versions when a package truly must diverge.
Example:
{ "dependencies": { "react": "catalog:", "zod": "catalog:" } }
Shared runtime dependencies
Be careful with shared runtime dependencies like
react, react-dom, or @tanstack/react-query.
- If a workspace lib and its consumers resolve different copies, you get duplicate runtime instances or type identity problems (e.g. broken hooks/context, confusing TypeScript errors).
- Libraries should declare shared runtimes as
; apps install the concrete version.peerDependencies - Use the catalog-pinned version by default. Avoid introducing separate versions casually.
Codegen Outputs
After running
pnpm --filter @workspace/api-spec run codegen, Orval writes the generated client to fixed paths:
lib/api-client-react/src/generated/api.tslib/api-client-react/src/generated/api.schemas.tslib/api-zod/src/generated/api.ts
The workspace barrels re-export those fixed filenames:
lib/api-client-react/src/index.tslib/api-zod/src/index.ts
The Orval config forces the OpenAPI title to
Api, so do not try to control generated filenames via info.title. If you touch the codegen config or scaffolded barrel files, keep them aligned with the fixed generated/api* filenames.
Common pitfalls
- Do not introduce an all-composite setup for leaf workspace packages. Declaration emit from apps causes type portability issues (TS2742) when multiple versions of
packages exist across workspace packages.@types/* - Do not add leaf workspace packages to the root
references; that solution file is for buildable libs only.tsconfig.json - Prefer root commands with
when targeting a specific package:--filterpnpm --filter @workspace/api-server run build
- If the editor and CLI disagree on cross-package types, trust
.pnpm run typecheck - If you change Orval output paths or the barrel exports, generated imports may break.
Artifact Lifecycle
If you are creating or updating an artifact, follow the
create-artifact skill for the presentArtifact and suggestDeploy() lifecycle instead of redefining it here.