Building a Multi-City Production Portal: Next.js 14 Monorepo with Dynamic City Routes and AWS Infrastructure

What Was Done

We scaffolded a Next.js 14 monorepo architecture for Rick Drake Productions — a multi-city production coordination platform launching with San Diego and Las Vegas, with Phoenix, Palm Springs, and LA on the roadmap. The project uses dynamic route segments to serve city-specific content from a single codebase while maintaining SEO-friendly URLs and independent branding per market.

Key accomplishments in this session:

  • Registered rickdrakeproductions.com via Route53 with privacy protection enabled
  • Configured pnpm workspaces across a monorepo structure
  • Built dynamic city-based routing with Next.js App Router
  • Scaffolded city-specific pages (services, fleet, contact, locations, portfolio)
  • Established type-safe content management with TypeScript
  • Configured Tailwind CSS 4 with native binary compilation

Technical Details: Monorepo Structure

The project follows a pnpm workspace pattern defined in pnpm-workspace.yaml:

packages:
  - 'apps/*'
  - 'packages/*'

This allows us to manage multiple applications (currently apps/web) and shared packages under one repository with hoisted node_modules and efficient disk usage.

The package.json at the root defines workspace dependencies and shared dev tools. The apps/web directory contains the Next.js 14 application with TypeScript and Tailwind CSS 4 configured in next.config.ts.

Dynamic City Routing Architecture

The core routing strategy uses Next.js dynamic segments. Directory structure:

apps/web/src/app/
├── page.tsx                    # Root homepage
├── [city]/
│   ├── layout.tsx              # City-specific wrapper
│   ├── page.tsx                # City homepage
│   ├── services/page.tsx
│   ├── fleet/page.tsx
│   ├── fleet/[vehicle]/page.tsx
│   ├── contact/page.tsx
│   ├── about/page.tsx
│   ├── locations/page.tsx
│   └── portfolio/page.tsx

The [city] dynamic segment captures the city slug from the URL path. This approach provides several advantages:

  • SEO benefits: URLs like /san-diego/services contain semantic keywords for geographic targeting
  • Code reuse: A single component tree handles all cities without duplication
  • Scalability: Adding Phoenix only requires adding city data; no new routes needed
  • Shared styling: Global CSS in globals.css applies to all city variants

Data Management: Cities and Content

We created type-safe data structures in apps/web/src/lib/types.ts to define the shape of city and content data. The apps/web/src/lib/cities.ts file exports a cities array:

export const cities = [
  { slug: 'san-diego', name: 'San Diego', state: 'CA' },
  { slug: 'las-vegas', name: 'Las Vegas', state: 'NV' }
];

Content-specific information lives in apps/web/src/lib/content.ts, which can be extended to fetch from a headless CMS, database, or static file system later. This separation allows Rick to eventually swap out the data layer without touching routing logic.

The [city]/layout.tsx validates that the requested city exists:

export async function generateStaticParams() {
  return cities.map(city => ({ city: city.slug }));
}

This ensures Next.js pre-renders all city routes at build time and prevents 404s for invalid cities.

Infrastructure: Domain and DNS

We registered rickdrakeproductions.com using AWS Route53 (not GoDaddy or Namecheap) for several reasons:

  • Unified infrastructure: DNS management lives in the same AWS account as future compute resources
  • Programmatic access: CloudFormation and Terraform can manage DNS records alongside other resources
  • No external handoff: Avoids sync issues between domain registrar and DNS provider
  • Privacy protection: Enabled at registration to protect Rick's personal details in WHOIS

The Route53 hosted zone was created during domain registration. DNS records will point to CloudFront distributions or application load balancers depending on the final deployment model.

Build Pipeline: Dependency Installation

Installing dependencies proved challenging on the development machine due to network constraints and optional native binaries. The final successful approach:

pnpm install --no-optional

This skipped optional dependencies like the sharp native binary (used for image optimization), reducing installation time. We later explicitly installed lightningcss-darwin-x64 to support Tailwind CSS 4's native CSS parsing on macOS.

The Next.js build completed successfully after resolving the lightningcss native binary. This validates that the project structure, TypeScript configuration, and Tailwind setup are correct.

Frontend Styling: Tailwind CSS 4

We configured Tailwind CSS 4 in apps/web/src/app/globals.css using the new @import syntax instead of the legacy @tailwind directives. Tailwind 4 compiles CSS natively for performance, which requires the lightningcss native binary for the target platform (darwin-x64 for Intel macOS, darwin-arm64 for Apple Silicon).

Navigation and footer components in apps/web/src/components/layout/ will use Tailwind utility classes to ensure consistent styling across all cities while allowing per-city overrides via CSS custom properties or component composition.

Current State and Next Steps

The local development environment is operational at http://localhost:3000/. The San Diego city page renders correctly, confirming that:

  • Dynamic routes resolve properly
  • Layout composition works across nesting levels
  • TypeScript compilation succeeds
  • Tailwind CSS applies styles correctly

Remaining work includes:

  • CloudFront distribution setup: Create a distribution for rickdrakeproductions.com pointing to the Next.js deployment (AWS Amplify, Vercel, or self-hosted)
  • SSL/TLS certificate: Request a wildcard certificate from ACM for rickdrakeproductions.com and *.rickdrakeproductions.com if using subdomain routing
  • Content population: Fill in services, fleet vehicles, locations, and portfolio items for each city
  • Analytics integration: Add Next.js analytics and site instrumentation
  • Old WordPress migration: Plan transition from sandiegoproductions.com's dated Visual Composer setup

The mon