```html

Building a Multi-City Next.js Portal: Domain Registration, Monorepo Architecture, and Dynamic Routing at Scale

Over the past development session, I built the foundational infrastructure for Drake Productions' multi-city web platform—a Next.js 14 application designed to power city-specific production coordination websites from a single codebase. This post walks through the technical decisions, infrastructure setup, and implementation details for engineers maintaining or extending this system.

What Was Done

  • Registered rickdrakeproductions.com via AWS Route53 with privacy protection enabled
  • Scaffolded a pnpm monorepo with Next.js 14 App Router in /apps/web
  • Implemented dynamic city-based routing using Next.js catch-all segments
  • Created type-safe city and content management layers
  • Set up foundational layout, navigation, and multi-page routing structure
  • Resolved native dependency issues with Tailwind CSS 4's lightningcss package

Domain Registration & DNS Architecture

Why Route53 over GoDaddy: The existing infrastructure uses AWS Route53 for DNS management (verified via commands checking 86from.com registration). Registering rickdrakeproductions.com in Route53 eliminates the need for domain nameserver handoffs between registrars and hosting infrastructure—a significant operational simplification. Route53 provides DNSSEC, alias records for CloudFront distributions, and integrated CloudWatch metrics out of the box.

Registration details: Domain registered with privacy protection enabled through Route53's privacy wrapper. Contact information was pre-populated from the existing 86from.com registration in the same account, maintaining consistency across the account's domain portfolio.

Future infrastructure: Once the build completes, the site will be hosted on CloudFront (likely reusing the existing distribution E2Q4UU71SRNTMB based on session notes) with Route53 alias records pointing to the CloudFront distribution endpoint. This provides global CDN acceleration and automatic failover capabilities.

Monorepo & Project Structure

Why pnpm + workspaces: The project uses pnpm-workspace.yaml (created at the repo root) to manage a monorepo. pnpm's hard-link deduplication reduces disk space significantly compared to npm/yarn when managing multiple applications. The workspace structure allows shared utilities, types, and components across apps while maintaining independent build pipelines.

Directory structure:

rickdrakeproductions.com/
├── pnpm-workspace.yaml
├── package.json
└── apps/
    └── web/
        ├── next.config.ts
        ├── tailwind.config.ts
        ├── tsconfig.json
        └── src/
            ├── app/
            │   ├── globals.css
            │   ├── layout.tsx (root layout)
            │   ├── page.tsx (hub homepage)
            │   └── [city]/
            │       ├── layout.tsx
            │       ├── 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
            ├── components/
            │   └── layout/
            │       ├── Nav.tsx
            │       └── Footer.tsx
            └── lib/
                ├── types.ts
                ├── cities.ts
                └── content.ts

Root vs. app-level layouts: The root layout.tsx at /apps/web/src/app/layout.tsx wraps the entire application with global metadata, font loading, and CSS. The city-level layout at /apps/web/src/app/[city]/layout.tsx handles city-specific context and inherited route structure for all city subpages.

Dynamic Routing with Catch-All Segments

Implementation: The routing strategy uses Next.js's optional catch-all segment pattern via the [city] directory. This allows URLs like:

  • rickdrakeproductions.com/san-diego/app/[city]/page.tsx
  • rickdrakeproductions.com/san-diego/services/app/[city]/services/page.tsx
  • rickdrakeproductions.com/las-vegas/fleet/vehicle-name/app/[city]/fleet/[vehicle]/page.tsx

Type safety: The cities.ts file defines a strict city union type and provides validation functions. The content.ts` module abstracts content fetching (placeholder for future CMS integration). Types are exported from types.ts and shared across components and pages, ensuring runtime safety when accessing city parameters from params.city.

Why this approach: A single codebase with parameterized routes scales better than managing separate subdomains (e.g., san-diego.rickdrakeproductions.com) from an ops perspective—no separate deployments, unified analytics, and simpler SSL certificate management (single cert covers all routes).

Build Issues & Dependency Resolution

The lightningcss problem: Tailwind CSS 4 requires the lightningcss native binary for CSS compilation. Installation initially failed because the platform-specific native binary (lightningcss-darwin-x64 for macOS ARM64) wasn't automatically resolved during pnpm install.

Solution: Explicitly installed the native binary package:

pnpm install lightningcss-darwin-x64 --save-peer

Then verified the Next.js build completed without CSS compilation errors. This is a common issue when Node.js optional dependencies don't auto-resolve on certain platforms; explicit installation ensures builds don't break in CI/CD environments with different architectures.

Key Architecture Decisions

  • Content layer abstraction: content.ts is designed to be swapped with a CMS client (Contentful, Sanity, etc.) without touching page components. This separation allows Rick to manage content independently later.
  • Shared navigation: The Nav.tsx component reads the cities list and renders links to all city hubs, maintaining consistency across the platform.
  • CSS strategy: Using Tailwind CSS 4 with globals.css importing Tailwind directives. This provides low-level customization for production styling while avoiding CSS-in-JS overhead.
  • Environment parity: Monorepo configuration with shared Node modules ensures build consistency across development, staging, and production.

What's Next

The foundation is solid. Immediate next steps:

  • CloudFront distribution update: Point the distribution's origin to the deployed Next.js app and add rickdrakeproductions.com + www.rickdrakeproductions.com