How Related Roadmaps Are Determined and Displayed Dynamically in the Developer Roadmap Repository

Related roadmaps are determined by a hardcoded list of slugs in each roadmap’s YAML front‑matter and displayed dynamically at request time by an Astro component that fetches all official roadmaps and filters them by those slugs.

The developer‑roadmap repository powers roadmap.sh, an open‑source learning path platform. The “Related Roadmaps” feature helps learners discover complementary skills by suggesting contextual links at the bottom of every roadmap page. This feature relies on static content definitions but resolves the actual roadmap data dynamically on every page load.

Front‑Matter Configuration

Content authors define relationships directly in the markdown files that store each roadmap. Every roadmap file (e.g., src/data/roadmaps/vue/vue.md) contains a relatedRoadmaps key in its YAML front‑matter that lists the URL slugs of other roadmaps to recommend.

---
title: Vue.js
relatedRoadmaps:
  - javascript
  - typescript
---

The front‑matter structure is strictly typed. In src/lib/roadmap.ts, the RoadmapFrontmatter interface declares the field as a string array:

export interface RoadmapFrontmatter {
  // ... other fields
  relatedRoadmaps?: string[];
}

This type safety ensures that only valid slugs can be assigned as related roadmaps during the content authoring process.

Data Flow and Type Safety

When a user visits a roadmap page at /[roadmapId], the application loads the full document via the officialRoadmapDetails query. The API response conforms to the OfficialRoadmapDocument type defined in src/queries/official-roadmap.ts, which mirrors the front‑matter structure:

export interface OfficialRoadmapDocument {
  // ... other fields
  relatedRoadmaps?: string[];
}

The page component located at src/pages/[roadmapId]/index.astro receives this data and forwards the relatedRoadmaps array to the presentation layer:

<RelatedRoadmaps relatedRoadmaps={roadmapData?.relatedRoadmaps || []} />

This separation of concerns keeps the routing layer agnostic of how the related roadmaps are resolved, while ensuring the UI component receives a clean list of slugs to process.

Runtime Resolution and Rendering

The dynamic behavior occurs inside src/components/RelatedRoadmaps.astro. Rather than relying on static props passed at build time, the component resolves the full roadmap objects at request time through the following steps.

First, it fetches the complete list of official roadmaps using the listOfficialRoadmaps() query, which hits the /v1-list-official-roadmaps endpoint:

import { listOfficialRoadmaps } from '../queries/official-roadmap';

const { relatedRoadmaps } = Astro.props;
const allRoadmaps = await listOfficialRoadmaps();

Next, it filters the full dataset to keep only the items whose slug property appears in the relatedRoadmaps prop:

const relatedRoadmapsDetails = allRoadmaps.filter((roadmap) =>
  relatedRoadmaps.includes(roadmap.slug),
);

Finally, the component maps over the filtered results to render interactive links. Because this filtering happens on every request, changes to a roadmap’s front‑matter are reflected instantly without requiring a site rebuild:

<div class="flex flex-col gap-1 pb-8">
  {relatedRoadmapsDetails.map((relatedRoadmap) => (
    <a
      href={`/${relatedRoadmap.slug}`}
      class="flex flex-col gap-0.5 rounded-md border bg-white px-3.5 py-2 hover:bg-gray-50 sm:flex-row sm:gap-0"
    >
      <span class="inline-block min-w-[195px] font-medium">
        {relatedRoadmap.title.card}
      </span>
      <span class="text-gray-500">{relatedRoadmap.description}</span>
    </a>
  ))}
</div>

This architecture allows content editors to define relationships declaratively in markdown while the system resolves and displays the current metadata (titles, descriptions) dynamically from the live data source.

Summary

  • Authoring: Content creators assign related roadmaps by listing slugs in the relatedRoadmaps front‑matter array within each roadmap’s markdown file.
  • Typing: The RoadmapFrontmatter interface in src/lib/roadmap.ts and the OfficialRoadmapDocument type in src/queries/official-roadmap.ts enforce type safety across the data pipeline.
  • Routing: The page component at src/pages/[roadmapId]/index.astro retrieves the roadmap document and passes the related slugs to the UI component.
  • Dynamic Resolution: RelatedRoadmaps.astro fetches all official roadmaps via listOfficialRoadmaps(), filters them by the provided slugs at runtime, and renders the matching items with current titles and descriptions.

Frequently Asked Questions

Edit the markdown file for the source roadmap (e.g., src/data/roadmaps/react/react.md) and add the target roadmap’s URL slug to the relatedRoadmaps array in the front‑matter. The change will appear on the next page load without requiring a full site rebuild.

Why does the component fetch all roadmaps instead of using static props?

The RelatedRoadmaps component calls listOfficialRoadmaps() at request time to ensure the displayed titles and descriptions are always current. If the related roadmap’s metadata changes (e.g., a title update), the dynamic resolution captures that change immediately, whereas static props would require a rebuild to reflect updates.

Where is the relationship data stored in the codebase?

The relationship definitions live as YAML front‑matter inside individual roadmap markdown files under src/data/roadmaps/*/*.md. The TypeScript interfaces that validate this data are located in src/lib/roadmap.ts, and the runtime filtering logic resides in src/components/RelatedRoadmaps.astro.

Currently, the system only supports manually curated relationships via the relatedRoadmaps front‑matter array. There is no automatic tagging or categorization logic in RelatedRoadmaps.astro; the component strictly filters by the explicit slug list provided by the content author.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →