Turborepo monorepo for emilshr.com (portfolio + Payload CMS) and burntclutchproject.com (Journeys travel blog). Dependency versions are centralized in the pnpm catalog (pnpm-workspace.yaml).
.
├── apps/
│ ├── portfolio/ # Next.js 16 + Payload CMS 3 (emilshr.com)
│ │ ├── src/ # App routes, collections, blocks, components
│ │ ├── scripts/ # Seed script
│ │ ├── seed-data/ # Markdown seed content
│ │ ├── tests/ # Vitest + Playwright
│ │ └── .env.example # Portfolio env vars
│ └── journeys/ # Next.js 16 travel blog (burntclutchproject.com)
│ ├── app/ # Minimal App Router surface
│ └── .env.example # Payload API URL for SDK
├── packages/
│ └── payload-types/ # Shared Payload-generated types (@repo/payload-types)
├── turbo.json # Turborepo task pipeline
├── pnpm-workspace.yaml # Workspace globs + dependency catalog
└── package.json # Root scripts (orchestrates via turbo)
| Package | Path | Port (dev) | Role |
|---|---|---|---|
portfolio |
apps/portfolio |
3000 | Main site, Payload admin, MongoDB, media |
journeys |
apps/journeys |
3001 | Travel blog; reads CMS via @payloadcms/sdk |
Payload types are generated once from the portfolio CMS config and written to packages/payload-types/payload-types.ts. Both apps import types from @repo/payload-types.
- Generate types:
pnpm generate:types(runspayload generate:typesinportfolio) - Config output path:
apps/portfolio/src/payload.config.ts→packages/payload-types/payload-types.ts - After adding collections/globals in Payload, regenerate types before using them in
journeys.
Shared versions live under catalog: in pnpm-workspace.yaml. Workspace packages reference them as "next": "catalog:" instead of pinning versions per package.json. To bump a dependency everywhere, change it once in the catalog and run pnpm install.
- Monorepo: Turborepo + pnpm workspaces
- CMS: Payload 3 + MongoDB (
portfolioonly) - Frontend: Next.js 16 (Chiri design on portfolio)
- Media: Cloudflare R2 (optional; local
public/mediafallback)
- Node.js
24.17.0(pinned viaengines) - pnpm
11.10.0(pinned viapackageManager) - Docker (for local MongoDB)
# MongoDB (portfolio)
docker compose up -d
# Env (portfolio CMS)
cp apps/portfolio/.env.example apps/portfolio/.env
# Install from repo root
pnpm install
# Run one app
pnpm dev:portfolio # http://localhost:3000 — admin at /admin
pnpm dev:journeys # http://localhost:3001
# Or run all dev servers
pnpm dev| Command | Description |
|---|---|
pnpm dev:portfolio |
Portfolio + Payload dev server |
pnpm dev:journeys |
Journeys dev server |
pnpm build |
Production build (all apps via Turbo) |
pnpm build --filter=portfolio |
Build portfolio only |
pnpm check-types |
Typecheck all packages |
pnpm lint |
ESLint all packages |
pnpm generate:types |
Regenerate @repo/payload-types |
pnpm payload |
Payload CLI in portfolio |
pnpm seed |
Seed portfolio DB from seed-data/ |
pnpm seed -- --freshPopulates posts, experiences, about, and homepage from apps/portfolio/seed-data/.
- Portfolio:
apps/portfolio/.env.example—MONGODB_URI,PAYLOAD_SECRET, R2, seed admin, etc. - Journeys:
apps/journeys/.env.example—PAYLOAD_API_URL(portfolio REST API base)
Two separate Vercel projects from this monorepo. Each app has a vercel.json with install/build commands from the repo root.
| App | Vercel root | Domain | Config |
|---|---|---|---|
portfolio |
apps/portfolio |
emilshr.com | apps/portfolio/.env.example |
journeys |
apps/journeys |
burntclutchproject.com | apps/journeys/.env.example |
Vercel project settings (both): Node.js 22.x; enable Include source files outside of the Root Directory (for packages/payload-types).
Portfolio env (production): MONGODB_URI (Atlas SRV), PAYLOAD_SECRET, NEXT_PUBLIC_SERVER_URL, R2 vars (required — no local disk on Vercel), Resend, JOURNEYS_SITE_URL, JOURNEYS_REVALIDATE_URL, REVALIDATE_SECRET.
Journeys env (production): PAYLOAD_API_URL and NEXT_PUBLIC_PAYLOAD_API_URL (both https://emilshr.com/api), NEXT_PUBLIC_SITE_URL (https://www.burntclutchproject.com), NEXT_PUBLIC_MEDIA_BASE_URL=https://emilshr.com, REVALIDATE_SECRET (set in Vercel dashboard only — not committed). Non-secret URLs are also defined in apps/journeys/vercel.json.
Journeys content: Edit homepage hero, about, and home sections in production Payload admin at https://emilshr.com/admin (Globals → Journeys Settings). Local CMS changes do not appear on burntclutchproject.com until saved against Atlas.
MongoDB: Migrate off Railway with mongodump / mongorestore to a free Atlas M0 cluster, then set MONGODB_URI on the portfolio project.
Seed: Run pnpm seed locally against Atlas; the deployed /next/seed route exceeds the Hobby 10s function limit.
- Wrong Next/Turbopack root: Both apps set
turbopack.rootto the monorepo root innext.config.ts. If builds fail to resolvenext, check that setting before changingnode_moduleslayout. - Missing Payload types: Run
pnpm generate:typesafter schema changes. Import from@repo/payload-types, not a localsrc/payload-types.ts. - Type errors on
declare module 'payload':packages/payload-types/index.tsmust keepimport 'payload'so augmentation resolves. - Filter by package name: Turbo filters use
package.jsonnamefields:portfolio,journeys,@repo/payload-types. - Payload skills: See
AGENTS.mdand.agents/skills/payload/for CMS-specific work.