Semantic URL Routing with Explicit Path Mapping
Context
Next.js Pages Router uses file-system-based routing: pages/technologies/[id].js creates routes at /technologies/:id. The portfolio has three dynamic route types: work experiences (/work-experiences/[id]), education entries (/educations/[id]), and technologies (/technologies/[id]). The API identifies records by MongoDB ObjectIds (24-character hexadecimal strings like 62cc232c40e2ca08bf885369), which are the natural candidates for the [id] parameter. However, using ObjectIds in URLs creates opaque, unmemorable paths (/technologies/62cc232c40e2ca08bf885369) that convey no semantic information to humans or search engines. The alternative is a friendlyUrl pattern where each record has a human-readable slug (/work-experiences/cto-at-loi) that maps to the ObjectId during data fetching. The ADR system (ADR-008) introduced a third pattern: local JSON records using friendlyUrl as the primary identifier with no ObjectId involvement.
Decision
Use MongoDB ObjectIds as the [id] parameter for API-backed dynamic routes (work experiences, educations, technologies), with the API responsible for lookup. Use friendlyUrl slugs as the [id] parameter for locally-stored records (ADRs), with the JSON array filtered by the slug field. The routing strategy mirrors the data source: API records use API identifiers, local records use local identifiers. getStaticPaths generates the full set of paths from the data source — either by fetching all records from the API or by mapping the local JSON array. getStaticProps receives the id parameter and fetches (or filters) the specific record. No catch-all routes ([...slug]) are used. No middleware rewrites translate between friendly URLs and ObjectIds. The URL structure directly reflects the data model's primary key strategy.
Consequences
Positive: For API-backed routes, the ObjectId in the URL is a stable, permanent identifier that never changes regardless of how the record's content evolves. Renaming a work experience title doesn't break the URL. The ObjectId provides a direct database lookup path with zero ambiguity. For ADRs, the friendlyUrl slug is human-readable and SEO-friendly, reflecting the decision's topic (e.g., /decisions/ssg-over-ssr). The dual strategy avoids forcing a single approach on fundamentally different data sources. No middleware or rewrite rules simplifies the routing surface — what you see in the file system is what you get in the URL. Negative: The ObjectId URLs for API-backed routes are ugly and unmemorable. /technologies/62cc232c40e2ca08bf885369 conveys nothing to the user about the page content. Search engines can parse these URLs but gain no keyword relevance from them. The inconsistency between ObjectId routes (API) and slug routes (ADRs) creates a dual mental model for the developer. Implementing friendlyUrl for API records would require: adding a slug field to every MongoDB document, ensuring uniqueness, handling slug conflicts, and migrating existing URLs. The effort is non-trivial for a feature that primarily benefits SEO and URL aesthetics — both legitimate concerns, but not critical for a portfolio site where traffic comes through direct links rather than organic search.
Predictions at Decision Time
Expected the ObjectId URLs to be acceptable because portfolio visitors arrive via direct links (shared URLs, LinkedIn) rather than manually typing URLs. Predicted the SEO impact of non-semantic URLs would be negligible for a personal portfolio. Assumed the inconsistency between ObjectId and slug routes would not confuse future development because the distinction maps cleanly to the data source.
Measured Outcomes
The ObjectId URLs have not generated any user feedback — confirming the prediction that visitors don't notice or care about URL aesthetics when following direct links. SEO impact is indeed negligible: Google indexes all pages regardless of URL format, and the portfolio ranks for name-based queries rather than keyword-based queries. The data source mapping (ObjectId = API, slug = local) has proven intuitive — when the ADR system was built, using friendlyUrl was the obvious choice precisely because it's local data with human-authored identifiers. The unexpected downside: sharing a technology page URL in conversation (e.g., in a meeting or email) requires copy-pasting the ObjectId URL because it's impossible to reconstruct from memory.
Unknowns at Decision Time
Did not know whether adding friendlyUrl slugs to API records would become necessary for a future feature (e.g., shareable portfolio sections, custom link building). If the portfolio is ever submitted to link aggregators or directories, semantic URLs would provide meaningful SEO advantage. Also unknown: whether Next.js would deprecate the Pages Router in favor of the App Router, which has different routing conventions — the dynamic route patterns would need to be re-evaluated in that context.
Reversibility Classification
Changing API-backed routes from ObjectId to friendlyUrl would break all existing URLs. Every shared link, every search engine index entry, and every bookmark pointing to /technologies/62cc232c40e2ca08bf885369 would 404. The migration would require: adding slug fields to all MongoDB documents, implementing 301 redirects from old ObjectId URLs to new slug URLs, and maintaining the redirect map permanently. The slug generation logic must handle conflicts and special characters. Estimated effort: 15-20 hours plus ongoing redirect maintenance. The reverse direction (ADR slugs to arbitrary IDs) would similarly break URLs but has a smaller impact surface.
Strongest Counter-Argument
Human-readable URLs are a fundamental web best practice. Every major platform (GitHub, Medium, dev.to) uses semantic slugs because they improve shareability, memorability, and SEO. A portfolio site for a CTO should demonstrate understanding of URL design as an architectural concern. The effort to add slugs to API records (estimated 8-10 hours for initial implementation) would be repaid in perpetuity through better URL aesthetics. The counter-counter: URL aesthetics optimize for a scenario (manual URL sharing, organic search) that the portfolio rarely encounters. The traffic arrives through LinkedIn, email, and direct links — channels where the URL is a hyperlink, not a typed string. Optimizing URL readability for these channels has zero functional value.
Technical Context
- No catch-all routes
- No middleware rewrites
- URL reflects data source primary key