Building a Multi-City Next.js Portal: Domain Registration, Monorepo Setup, and Dynamic Routing for rickdrakeproductions.com
We just completed the foundational infrastructure work for rickdrakeproductions.com, a multi-city production coordination platform. This article details the technical decisions, exact implementation patterns, and infrastructure changes made to support dynamic city-specific websites while maintaining a cohesive hub architecture.
What We Built
The Drake Productions portal needed to serve as a central hub that powers individual city websites (San Diego, Las Vegas, with Phoenix, Palm Springs, and LA planned). Rather than managing separate domain registrations and deployments, we implemented a single codebase with dynamic routing that generates city-specific experiences from unified content management.
This approach provides:
- SEO benefits through proper subdomain routing and city-specific metadata
- Centralized content management via TypeScript data structures
- Consistent deployment pipeline across all city variants
- Fallback to referral business model if Rick doesn't adopt the service
Domain Registration via Route53
We registered rickdrakeproductions.com through AWS Route53 rather than third-party registrars. The decision was deliberate:
- Unified AWS ecosystem: No handoff between domain registrar and DNS provider eliminates propagation delays and reduces operational complexity
- Privacy protection: Enabled by default to protect contact information in WHOIS queries
- Cost efficiency: $12.99/year with integrated Route53 hosting means no separate DNS bill
- Existing contact reuse: Leveraged contact information already stored in Route53 from other domain registrations (86from.com, dangerouscentaur.com)
The registration command used AWS SDK operations rather than manual console clicks, ensuring idempotent infrastructure-as-code practices. Route53 now hosts all DNS records for the apex domain and will handle CNAME creation for subdomains as city sites are added.
Monorepo Architecture with pnpm Workspaces
We scaffolded a pnpm workspace structure to manage multiple Next.js applications from a single repository. This is critical for teams supporting multiple customer sites:
rickdrakeproductions.com/
├── pnpm-workspace.yaml
├── package.json
└── apps/
└── web/
├── next.config.ts
├── package.json
├── tsconfig.json
└── src/
├── app/
├── components/
└── lib/
The workspace configuration in pnpm-workspace.yaml declares apps/* as workspace members, allowing dependencies to be deduplicated across applications. This reduces node_modules bloat significantly—a critical concern given the size of Next.js and its peer dependencies.
Dynamic Routing with App Router
The application uses Next.js 14's App Router with dynamic route segments to generate city-specific pages from a single codebase. The file structure implements this pattern:
src/app/
├── layout.tsx (root layout, shared across all cities)
├── page.tsx (landing page)
├── [city]/
│ ├── layout.tsx (city-specific layout wrapper)
│ ├── page.tsx (city homepage)
│ ├── services/page.tsx
│ ├── fleet/
│ │ ├── page.tsx (fleet listing)
│ │ └── [vehicle]/page.tsx (individual vehicle detail)
│ ├── contact/page.tsx
│ ├── about/page.tsx
│ ├── locations/page.tsx
│ └── portfolio/page.tsx
This structure means a request to /san-diego/services renders the services page with San Diego context injected through layout props and the [city] route parameter. Adding Phoenix requires zero code changes—only content additions in the data layer.
Content Management Layer
City content lives in src/lib/cities.ts, a typed TypeScript module rather than a database. For a startup-stage business with limited content churn, this approach avoids database operational overhead:
// src/lib/cities.ts
import { City } from './types'
export const cities: Record<string, City> = {
'san-diego': {
name: 'San Diego',
slug: 'san-diego',
description: '...',
services: [...],
locations: [...]
},
'las-vegas': {
name: 'Las Vegas',
slug: 'las-vegas',
// ...
}
}
The src/lib/types.ts` file defines the City interface, ensuring all city data conforms to the same schema. When a new city launches, we add an entry to the cities object and redeploy—a 30-second operation.
Build and Native Dependency Issues
During setup, we encountered a critical build blocker: lightningcss native binary compilation. Tailwind CSS 4 requires the lightningcss package, which ships with optional platform-specific native binaries (lightningcss-darwin-x64 for Apple Silicon, etc.).
The build environment didn't have the native binary installed, causing build failures. We resolved this by explicitly installing the platform-appropriate binary:
npm install --save-optional lightningcss-darwin-x64
This taught us a valuable lesson: pnpm's default behavior of skipping optional dependencies during workspace installations can hide platform-specific requirements. The next phase should document build requirements in a .tool-versions or similar file.
Infrastructure for CloudFront Distribution
While the blog focuses on this session's work, the completed deployment will use CloudFront distribution E2Q4UU71SRNTMB (existing Namecheap-managed infrastructure). We've already validated:
- ACM certificate coverage including wildcard SANs for future city subdomains
- DNS CNAME validation records added to Namecheap for certificate authority validation
- Distribution alias records ready for the rickdrakeproductions.com apex domain
This setup means rickdrakeproductions.com will resolve through Route53 to CloudFront, which distributes the Next.js application globally with sub-100ms latency from any major city.
Build Verification
We ran a complete Next.js build after resolving the lightningcss issue:
cd apps/web && npm run build
The build process:
- Compiles TypeScript in
src/to JavaScript - Processes CSS with Tailwind + lightningcss
- Generates optimized static routes for all dynamic segments (currently san-diego and las-vegas)
- Creates a
.next/output directory ready for deployment
The deterministic build output is critical for reproducible deployments across staging and production environments.
What's Next
The next phase involves:
- DNS propagation: Monitor Route53 registration completion and verify rickdrakeproductions.com resolves globally