Wiki Routing and Pages

Purpose and Scope

OpenWiki exposes each generated wiki as ordinary Next.js routes under an owner and repository name. The route pair is intentionally small: the repository root renders the overview-style wiki page, while an additional slug segment renders a specific generated page. This gives readers predictable URLs such as /vercel/next.js for the repository landing page and /vercel/next.js/routing for a particular page. The route files do not duplicate wiki rendering logic; they translate URL parameters into a shared server component that knows how to load repository artifacts, choose the active page, and assemble the wiki interface.

Sources: app/(wiki)/[owner]/[repo]/page.tsx, app/(wiki)/[owner]/[repo]/[slug]/page.tsx, app/repos/[owner]/[repo]/repository-wiki-page.tsx

The home experience is also part of the routing story because it is the primary way many users reach a wiki route. The client-side repository home component accepts featured repository cards, refreshes their metadata, validates direct GitHub repository URLs, and searches public repositories when the input is not already a full URL. Once a repository is selected or entered, the routing helpers normalize it into the same owner/repo path shape used by the public wiki pages. This keeps typed URLs, featured cards, and search results aligned around one canonical wiki address.

Sources: app/components/repository-home.tsx

Relevant Source Files

  • app/(wiki)/[owner]/[repo]/page.tsx - Defines the repository-root wiki route, static generation settings, metadata generation for the default page, and the handoff to RepositoryWikiPage without a slug.
  • app/(wiki)/[owner]/[repo]/[slug]/page.tsx - Defines individual wiki page routes, resolves the slug from route params, generates page-specific metadata, and passes the slug into the shared renderer.
  • app/(wiki)/static-params.ts - Provides static parameter helpers for featured repositories and published wiki slugs so selected public wiki routes can be generated ahead of time.
  • app/repos/[owner]/[repo]/repository-wiki-page.tsx - Implements the shared server-side wiki page renderer, including storage lookup, error states, redirects, navigation state, auto-indexing fallback, and page chrome.
  • app/components/repository-home.tsx - Implements the client-side landing/search UI that sends users toward canonical repository routes and refreshes featured repository metadata.

Route Structure and Static Generation

The repository root route is implemented by app/(wiki)/[owner]/[repo]/page.tsx. It receives owner and repo from a promised params object, exports dynamic = "force-static", keeps dynamicParams = true, and sets revalidate = false. Together, those settings express that OpenWiki wants static output for known paths while still allowing repositories beyond the prerendered set to be requested. Its generateStaticParams delegates to getFeaturedWikiStaticParams, so featured repositories are the primary root pages considered during build-time parameter generation.

Sources: app/(wiki)/[owner]/[repo]/page.tsx, app/(wiki)/static-params.ts

The slug route follows the same pattern in app/(wiki)/[owner]/[repo]/[slug]/page.tsx, but extends the route parameters with slug. Its generateStaticParams calls getFeaturedWikiSlugStaticParams, which is asynchronous because it can read published wiki page slugs from storage. This distinction matters operationally: repository roots can be derived directly from configured featured repository URLs, while individual wiki pages depend on generated artifacts that may or may not exist when the build runs.

Sources: app/(wiki)/[owner]/[repo]/[slug]/page.tsx, app/(wiki)/static-params.ts

The static parameter helper first normalizes featured repository definitions. It parses each featured repoUrl, discards invalid entries, and deduplicates by repository full name before returning { owner, repo } objects. For slug pages, it passes the normalized featured repositories into listPublishedWikiRouteParams. If that storage-backed lookup fails, the helper logs a warning and returns an empty list rather than failing route generation. That fallback keeps the app build resilient when published artifacts are temporarily unavailable, while still allowing dynamic params to serve paths later.

Sources: app/(wiki)/static-params.ts

Shared Repository Wiki Renderer

Both public route files render RepositoryWikiPage, which centralizes the behavior that should be identical between the overview route and every slug route. The component accepts owner, repoName, and an optional slug, then calls getRepositoryWiki({ name: repoName, owner, slug }). This storage call is the boundary between routing and generated content. Route files are responsible for URL shape and metadata; the shared renderer is responsible for interpreting repository state, current page state, and the UI a reader should see for that state.

Sources: app/(wiki)/[owner]/[repo]/page.tsx, app/(wiki)/[owner]/[repo]/[slug]/page.tsx, app/repos/[owner]/[repo]/repository-wiki-page.tsx

The renderer handles several repository states explicitly. Storage configuration errors return a storage configuration page, artifact-unavailable errors return an artifact unavailable page, and unexpected errors are rethrown. If a slug was requested and no wiki exists, the component calls notFound(). If a wiki exists with pages, but the requested slug does not match a current page, it redirects back to the repository root. That distinction gives unknown repositories an opportunity to index from the root route, while treating invalid page slugs for an existing wiki as navigational mistakes.

Sources: app/repos/[owner]/[repo]/repository-wiki-page.tsx

When there is no stored wiki, the renderer creates an empty repository wiki model and checks whether repository creation is disabled. If public creation is disabled, it renders a read-only disabled state. Otherwise, it renders RepositoryAutoIndex, giving the route itself the ability to start or present indexing progress for a repository that has not yet been generated. This is why visiting a repository route directly is a supported workflow: the route is not only a reader page, but also an entry point into wiki generation for public repositories.

Sources: app/repos/[owner]/[repo]/repository-wiki-page.tsx

Metadata, Navigation, and Page State

Metadata is generated before the shared renderer runs. The root route calls getWikiOgData with a fallback page title of Overview, while the slug route calls titleFromWikiSlug(slug) to derive a readable fallback title. Both routes then pass the returned data into createWikiMetadata. This keeps Open Graph and document metadata consistent with the current wiki page when stored wiki data is available, but still gives routes useful titles when storage does not yet provide page-specific metadata.

Sources: app/(wiki)/[owner]/[repo]/page.tsx, app/(wiki)/[owner]/[repo]/[slug]/page.tsx

Inside the renderer, the active page is derived from wiki.currentPage. If no current page is available, activeSlug falls back to overview. The component builds currentPageHref with a local getWikiPageHref helper and builds the repository root href with getRepoHref. It also constructs a chat link by appending /chat to the repository root. These derived links feed the navbar model, so the app can present wiki and chat modes for the same repository without each route file knowing about the complete UI shell.

Sources: app/repos/[owner]/[repo]/repository-wiki-page.tsx

The renderer imports and wires the UI components that make a repository wiki usable: OpenWikiNavbar for the shell, MobileWikiNav for compact navigation, PersistentScrollArea for stable scroll behavior, CopyMarkdownButton for markdown export affordances, RepoChat for repository chat, and WikiMarkdown for rendering generated markdown. The snippet also shows a table-of-contents extraction step based on the current page markdown. The important routing implication is that a wiki page is not a simple markdown blob; it is a page state assembled with repository metadata, navigation, source-rendered content, and adjacent actions.

Sources: app/repos/[owner]/[repo]/repository-wiki-page.tsx

Repository Home Entry Points

RepositoryHome is a client component because it manages interactive input, search status, and navigation from the browser. It initializes from initialFeaturedRepositories, then fetches /api/repositories/featured with cache: "no-store" to refresh card metadata after hydration. For text input, it keeps a repoUrl state value synchronized with the q search parameter. If the trimmed value is at least two characters and is not parseable as a GitHub repository URL, the component treats it as a search query rather than a direct route target.

Sources: app/components/repository-home.tsx

The search behavior uses an abortable, delayed fetch to /api/repositories/search?q=..., then stores repository results or an error status. Direct URLs are parsed with parseGitHubRepoUrl, while canonical wiki destinations are built with getRepoHref. This design means the landing page can support two related tasks without creating separate route conventions: a reader can paste a complete GitHub repository URL, or they can search by name and select a result. Either way, the final destination is the same owner/repo wiki route handled by the server components.

Sources: app/components/repository-home.tsx

Compact Reference

ConcernSource-level contract
Repository root wiki routeapp/(wiki)/[owner]/[repo]/page.tsx renders RepositoryWikiPage owner={owner} repoName={repoName} and uses getFeaturedWikiStaticParams() for static params.
Wiki slug routeapp/(wiki)/[owner]/[repo]/[slug]/page.tsx renders RepositoryWikiPage owner={owner} repoName={repoName} slug={slug} and uses getFeaturedWikiSlugStaticParams().
Static modeBoth wiki routes export dynamic = "force-static", dynamicParams = true, and revalidate = false.
Root metadata fallbackThe root route passes fallbackPageTitle: "Overview" to getWikiOgData.
Slug metadata fallbackThe slug route passes fallbackPageTitle: titleFromWikiSlug(slug) to getWikiOgData.
Featured root paramsgetFeaturedWikiStaticParams() returns { owner, repo } entries from parsed, deduplicated featured repository URLs.
Featured slug paramsgetFeaturedWikiSlugStaticParams() asks storage for listPublishedWikiRouteParams(repositories) and returns [] if that lookup fails.
Wiki data lookupRepositoryWikiPage calls getRepositoryWiki({ name: repoName, owner, slug }).
Missing slug wikiIf storage returns null for a slug request, RepositoryWikiPage calls notFound().
Unknown page within existing wikiIf a slug is present, pages exist, and currentPage is null, the renderer redirects to getRepoHref({ name: repoName, owner }).
Empty repository routeIf there are no pages and no current page, the renderer shows either repository creation disabled state or RepositoryAutoIndex.

Execution Flow

A typical direct wiki request starts when a browser asks for /owner/repo or /owner/repo/slug. Next.js resolves the matching route file, awaits route params, prepares metadata using the Open Graph helper, and renders the shared repository wiki page. The shared renderer then loads the wiki from storage, normalizes the active slug, derives repository and chat links, builds navigation context, and chooses between empty, unavailable, redirected, not-found, or full wiki content states. This flow keeps URL interpretation thin and content decisions centralized.

Sources: app/(wiki)/[owner]/[repo]/page.tsx, app/(wiki)/[owner]/[repo]/[slug]/page.tsx, app/repos/[owner]/[repo]/repository-wiki-page.tsx

For maintainers, the main rule is to add route behavior at the correct layer. Changes to path shape, static generation, or route metadata belong in the files under app/(wiki). Changes to storage interpretation, empty repository behavior, navigation state, or rendered wiki chrome belong in RepositoryWikiPage. Changes to how users discover or enter repositories from the landing page belong in RepositoryHome. Keeping those responsibilities separated makes it easier to adjust generation, publishing, and UI behavior without accidentally changing the public URL contract.

Sources: app/(wiki)/[owner]/[repo]/page.tsx, app/(wiki)/[owner]/[repo]/[slug]/page.tsx, app/(wiki)/static-params.ts, app/repos/[owner]/[repo]/repository-wiki-page.tsx, app/components/repository-home.tsx

Next Steps

If you are changing public wiki URLs, review the static parameter helpers before touching the renderer. If you are changing what readers see on a wiki page, start in RepositoryWikiPage and confirm how currentPage, pages, and navigation are used. If you are changing repository discovery, work from RepositoryHome and keep getRepoHref as the bridge to canonical wiki routes. Related areas include featured repository prerendering, markdown export, repository chat routes, and internal revalidation, because all of those features depend on the same owner/repo/slug address model.