Routing System
Relevant source files
The following files were used as context for generating this wiki page:- [src/pages/[...slug].tsx](https://github.com/Alonso-pixel/railways-docs/blob/HEAD/src/pages/%5B...slug%5D.tsx)
- [src/pages/dynamic/[...slug].tsx](https://github.com/Alonso-pixel/railways-docs/blob/HEAD/src/pages/dynamic/%5B...slug%5D.tsx)
- src/middleware.ts
- redirects.js
- contentlayer.config.ts
- src/data/sidebar.ts
The routing system for the Railway Documentation is built upon Next.js, leveraging its file-based routing, Static Site Generation (SSG), and Server-Side Rendering (SSR) capabilities. The system is designed to serve documentation pages from Markdown files, handle redirects for legacy URLs, and provide raw Markdown content on demand through content negotiation.
At its core, the system uses catch-all routes to handle documentation pages. A custom middleware intercepts incoming requests to determine the appropriate response format (HTML or Markdown) and rewrites URLs to a dynamic route handler when necessary. Page slugs and navigation structure are centrally managed, ensuring a coherent and navigable documentation site.
Core Routing Components
The routing architecture is primarily composed of Next.js pages, a middleware function, and content source configuration.
This diagram illustrates the relationship between the key files involved in routing and content delivery.
Sources: src/middleware.ts, [src/pages/[...slug].tsx](), [src/pages/dynamic/[...slug].tsx](), contentlayer.config.ts, redirects.js, src/data/sidebar.ts
Page Implementations
The system uses two different catch-all route files to handle page rendering, each with a distinct rendering strategy.
| File | Rendering Strategy | Key Functions | Description |
|---|---|---|---|
src/pages/[...slug].tsx | Static Site Generation (SSG) | getStaticProps, getStaticPaths | Pre-renders all documentation pages at build time for fast delivery. It generates paths from the allPages collection provided by Contentlayer. |
src/pages/dynamic/[...slug].tsx | Server-Side Rendering (SSR) | getServerSideProps | Renders pages on-demand. This route is used by the middleware to handle requests for raw Markdown content. |
Sources: [src/pages/[...slug].tsx:49-67](), [src/pages/dynamic/[...slug].tsx:62-90]()
Middleware and Content Negotiation
A key feature of the routing system is the middleware that intercepts all incoming requests. Its primary responsibility is to determine if a request for a documentation page should be served as a standard HTML page or as raw Markdown text.
Sources: src/middleware.ts
Middleware Logic Flow
The middleware follows a specific logic to process each request:
- It ignores any requests to API routes (paths starting with
/api/). - It checks if the requested path corresponds to a known documentation page.
- It determines if the client is requesting Markdown. This is true if:
- The path ends with
.md. - The query parameter
format=mdis present. - The
Acceptheader preferstext/markdownortext/plainovertext/html.
- The path ends with
- If Markdown is requested, it rewrites the URL to the
/dynamic/[...slug]route, addingformat=mdto the query string. - Otherwise, it allows the request to proceed to the standard SSG page handler.
The following diagram visualizes this flow:
Sources: src/middleware.ts:14-34
Dynamic SSR Handler
The dynamic/[...slug].tsx page is responsible for handling these rewritten requests. When it detects the format=md query parameter, instead of rendering an HTML page, it constructs the full Markdown content (including frontmatter) and sends it directly in the response with a text/markdown content type.
// src/pages/dynamic/[...slug].tsx:73-81
if (context.query.format === "md") {
const markdown = reconstructMarkdownWithFrontmatter(
{ title: page.title, description: page.description, url: page.url },
page.body.raw
);
context.res.setHeader("Content-Type", "text/markdown; charset=utf-8");
context.res.write(markdown);
context.res.end();
return { props: {} };
}
Sources: [src/pages/dynamic/[...slug].tsx:73-81]()
Static Page Generation (SSG)
For standard web traffic, documentation pages are pre-rendered at build time using Static Site Generation (SSG).
Path and Content Generation
getStaticPaths: This function insrc/pages/[...slug].tsxretrieves all possible page URLs from theallPagesobject, which is generated by Contentlayer. This tells Next.js which pages to pre-render.
Sources: [src/pages/[...slug].tsx:60-67]()- Contentlayer: The
contentlayer.config.tsfile defines how Markdown files insrc/docsare processed. It extracts fields liketitleanddescriptionand computes the final URL for each page.
Sources: contentlayer.config.ts:5-24 getStaticProps: For each path, this function finds the corresponding page data fromallPagesand passes it as props to the page component for rendering.
Sources: [src/pages/[...slug].tsx:49-58]()
This sequence diagram shows the data flow during the build process for SSG pages.
Sources: [src/pages/[...slug].tsx:49-67](), contentlayer.config.ts
Redirects
The application handles legacy URLs and path changes through a centralized redirect configuration. The redirects.js file exports an array of redirect objects that are consumed by the Next.js configuration.
Sources: redirects.js
Redirect Configuration
The system supports both standard and hash-based redirects.
| Type | Source Example | Destination Example |
|---|---|---|
| Path Redirect | /getting-started | /quick-start |
| Path with Slug | /develop/:slug* | /guides/:slug* |
| Hash Redirect | #application-failed-to-respond | /reference/errors/application-failed-to-respond |
// redirects.js
const redirects = [
{
source: "/getting-started",
destination: "/quick-start",
permanent: true,
},
{
source: "/develop/:slug*",
destination: "/guides/:slug*",
permanent: true,
},
];
const hashRedirects = [
{
source: "#application-failed-to-respond",
destination: "/reference/errors/application-failed-to-respond",
permanent: true,
},
];
Sources: redirects.js:1-13, 81-85
Summary
The routing system in railways-docs is a robust and flexible solution built on Next.js. It effectively combines Static Site Generation for performance with Server-Side Rendering and middleware for dynamic functionality like content negotiation. By centralizing page definitions in Contentlayer and sidebar.ts, and managing legacy paths via redirects.js, the system provides a maintainable and efficient way to deliver documentation content in multiple formats.