Context
I want to host incubating projects (like Asset Tracker) under subdomains
(e.g., assettracker.robbiepalmer.me) while keeping them within the same
Next.js application and Cloudflare Pages deployment.
Incubating projects within the same Next.js app provides advantages:
- Shared Components: New projects can import existing UI components, layouts, and utilities directly.
- Shared Configuration: Tailwind theme, TypeScript config, ESLint rules, and build setup are inherited automatically.
- Automatic Improvements: Dependency upgrades and infrastructure changes benefit all projects without keeping separate packages in sync.
- Single Deployment: One Cloudflare Pages project with unified preview deployments for all changes.
Decision
Rejected. After investigation, subdomain routing within a single Cloudflare Pages project is not feasible with static site generation.
What We Tried
Cloudflare Transform Rules can rewrite URI paths at the edge:
resource "cloudflare_ruleset" "assettracker_rewrite" {
zone_id = data.cloudflare_zone.domain.id
name = "Assettracker subdomain rewrite"
kind = "zone"
phase = "http_request_transform"
rules {
action = "rewrite"
expression = "(http.host eq \"assettracker.robbiepalmer.me\") and not starts_with(http.request.uri.path, \"/_next\")"
action_parameters {
uri {
path {
expression = "concat(\"/assettracker\", http.request.uri.path)"
}
}
}
}
}Why It Didn't Work
Pages custom domains bypass zone-level transform rules. When a custom domain is registered with a Pages project, Pages intercepts requests before the transform rule applies. Pages then returns a 308 redirect because it can't find content at the root path.
Without the Pages custom domain, requests fail with 522 (connection timeout) because Pages doesn't accept requests for unregistered hostnames.
Future Approach
When Asset Tracker "graduates" to its own Cloudflare Pages project:
- Create a separate Pages project for assettracker
- Register
assettracker.robbiepalmer.meas its custom domain - Deploy assettracker as a standalone Next.js app at root path
/ - No transform rules needed - subdomain maps directly to the project
This preserves SSG benefits and avoids the complexity of runtime routing.
Alternatives Considered
Middleware / Runtime Routing
- Pros: Next.js middleware can route by hostname natively.
- Cons: Requires a runtime, breaking Static Site Generation. Would need either Vercel or Cloudflare Workers (via
@opennextjs/cloudflare). - Decision: Rejected - SSG constraint takes priority.
Path-Based Routing
- Pros: Works with single Pages project and SSG. No infrastructure complexity.
- Cons: Less clean URLs (
robbiepalmer.me/assettrackervsassettracker.robbiepalmer.me). - Decision: Accepted for now. Subdomains can be added when projects graduate to separate deployments.
Consequences
Current State
Asset Tracker lives at robbiepalmer.me/assettracker.
This is acceptable for an incubating project.
The path-based approach keeps infrastructure simple while allowing rapid iteration.
Future Graduation Path
When a project needs its own subdomain:
- Extract to separate repository
- Create dedicated Cloudflare Pages project
- Subdomain "just works" without transform rules
- Static site benefits preserved throughout