Building a Multi-City Production Platform with Next.js 14: From Domain Registration to Dynamic Route Architecture
What Was Done
We built the foundational architecture for Drake Productions' multi-city portal—a Next.js 14 application that serves as the hub for city-specific production coordination websites. The project consolidates what were previously separate WordPress sites (sandiegoproductions.com dating back to 2016) into a unified, maintainable platform anchored at rickdrakeproductions.com, with dynamic city-specific pages and subdomains.
Key accomplishments in this session:
- Registered rickdrakeproductions.com domain via Route53 with privacy protection
- Scaffolded a pnpm monorepo workspace structure with Next.js 14, TypeScript, and Tailwind CSS 4
- Implemented dynamic routing for city-specific content using Next.js App Router catch-all routes
- Built reusable component architecture (Nav, Footer) with city context awareness
- Created type-safe city and content management systems
- Verified local development environment at http://localhost:3000/san-diego/
Technical Details: Architecture & Implementation
Domain & Infrastructure Foundation
We registered rickdrakeproductions.com through AWS Route53 rather than a third-party registrar. This decision eliminated domain-registrar-to-DNS-provider handoff complexity and kept everything within the AWS ecosystem. Route53 provides automatic DNS management alongside domain registration, reducing operational overhead when pointing to CloudFront distributions or updating records for certificate validation.
The domain was registered with privacy protection enabled, protecting WHOIS data while maintaining proper contact information in the registrar's backend for administrative purposes.
Monorepo Structure & Package Management
The project uses pnpm as the workspace manager over npm or yarn. This decision prioritizes disk space efficiency (hard links instead of copying packages) and faster installation times—critical for CI/CD pipelines. The workspace file structure:
/Users/cb/Documents/repos/sites/rickdrakeproductions.com/
├── pnpm-workspace.yaml
├── package.json
└── apps/
└── web/
├── next.config.ts
├── package.json
└── src/
├── app/
├── components/
├── lib/
└── ...
The pnpm-workspace.yaml defines workspace dependencies and allows future apps (api, admin, etc.) to share common dependencies without duplication.
Next.js 14 App Router with Dynamic City Routes
The most important architectural decision: using catch-all dynamic routes with the filename pattern [city] to serve city-specific content from a single codebase.
Directory structure:
src/app/
├── page.tsx # Root homepage
├── layout.tsx # Global layout, Nav, Footer
├── globals.css # Tailwind directives
├── [city]/
│ ├── layout.tsx # City-specific layout wrapper
│ ├── page.tsx # City homepage (e.g., /san-diego/)
│ ├── services/
│ │ └── page.tsx # /[city]/services/
│ ├── fleet/
│ │ ├── page.tsx # /[city]/fleet/ (list all vehicles)
│ │ └── [vehicle]/
│ │ └── page.tsx # /[city]/fleet/[vehicle]/ (detail)
│ ├── contact/
│ │ └── page.tsx
│ ├── about/
│ │ └── page.tsx
│ ├── locations/
│ │ └── page.tsx
│ └── portfolio/
│ └── page.tsx
This structure allows a single [city] route handler to support routes like:
/san-diego//san-diego/services/san-diego/fleet/truck-01/las-vegas//las-vegas/portfolio
Type-Safe City & Content Management
We created src/lib/types.ts to define the shape of city and content data:
// Defines city metadata, service offerings, fleet inventory, etc.
// Ensures type safety across all city-specific pages
And src/lib/cities.ts to maintain a canonical list of supported cities:
// Exports city configuration including:
// - City slug (san-diego, las-vegas, etc.)
// - Display name
// - Contact info
// - Service areas
// - Fleet assignments
The src/lib/content.ts file manages page content and metadata. By centralizing content here rather than spreading it across components, we enable easy migration to a CMS (Contentful, Strapi, etc.) later without refactoring routes.
Component Architecture
Reusable layout components in src/components/layout/:
Nav.tsx: Navigation aware of current city context; links to city-specific sectionsFooter.tsx: Global footer with city-specific contact info / location links
Both components accept city context via props or React Context, enabling them to render city-specific links without hardcoding routes.
Styling: Tailwind CSS 4 with Lightning CSS
The project uses Tailwind CSS 4, which requires the lightningcss native binary for CSS processing. This caused initial build failures due to missing platform-specific binaries. We resolved this by explicitly installing lightningcss-darwin-x64 for macOS development environments, ensuring the native parser is available at build time.
Global styles in src/app/globals.css include Tailwind directives and custom CSS variables for theming across city sites.
Infrastructure & Deployment Readiness
The Next.js build successfully compiles to static and dynamic routes, ready for deployment to AWS infrastructure. The next phase involves:
- CloudFront distribution pointing rickdrakeproductions.com → Next.js deployment (Vercel, EC2, or ECS)
- SSL certificate covering rickdrakeproductions.com and city-specific subdomains if needed
- Route53 alias records for both root domain and potential subdomains (sd.rickdrakeproductions.com, lv.rickdrakeproductions.com, etc.)
Key Architectural Decisions & Rationale
- Single codebase, dynamic routing: Rather than maintaining separate repos for each city, one codebase scales to 5, 10, or 50 cities with configuration changes only.
- pnpm over npm: Faster CI/CD, smaller disk footprint, native monorepo support.
- Route53 domain registration: Eliminates DNS provider switching; integrates directly with CloudFront and ACM certificates.
- Content abstraction layer: cities.ts and content.ts separate data from presentation, enabling future CMS integration.