GioJSdocs
On this page

getStaticPaths

List the params a dynamic page is exported for when gio export writes a static site.

app/posts/[id]/page.tsx
import type { GetStaticPaths } from '@gio.js/core';
import { db } from '../../../lib/db.server.ts';

export const getStaticPaths: GetStaticPaths<'/posts/:id'> = async () => {
  const ids = await db.posts.allIds();
  return { paths: ids.map((id) => ({ params: { id } })) };
};

A static host has no server to render /posts/42 on demand, so gio export needs the list up front. It calls getStaticPaths once per dynamic page and renders one HTML file per entry. The GioJS server never calls it: there, any params render on demand.

Reference

Returns

getStaticPaths takes no arguments and returns (or resolves to) { paths }:

FieldTypeDefaultDescription
paths (required)Array<{ params }>-One entry per page to write.
paths[].params (required)StaticParamsOf<Route>-A value for every dynamic segment of the route. [id] takes a string. A catch-all ([...slug]) takes the path below it as one string ('guides/setup') or as its segments (['guides', 'setup']). An optional catch-all ([[...slug]]) may also be left out, '' or [], for the bare parent path.

Behavior

  • Each entry becomes a URL path, and the page renders for it as on the server - getServerSideProps and generateMetadata included - with the params filled in and no query, headers or cookies. /posts/1 is written to out/posts/1/index.html.
  • An invalid entry is skipped with a reason, and the rest are exported:
    • getStaticPaths entry is missing param "id"
    • param "id" is a single segment but "a/b" contains '/'
    • param "slug" has an empty, relative or backslashed segment: "../x" - nothing is ever written outside out/
  • A rendered entry that answers 404 (notFound()) is skipped (notFound() - nothing written), and so is a redirect (redirect (303) - server only) or a render error (with its error reference).
  • A dynamic page without getStaticPaths is skipped: dynamic route without getStaticPaths().
  • If getStaticPaths throws or rejects, gio export stops with the error and exits with code 1.

Types

GetStaticPaths<Route> types the function and checks every entry against the route's params; Route is a pattern of your app ('/posts/:id', '/docs/*slug', '/shop/*path?') or a params shape. StaticPathsResult<Route> types the result alone.

Examples

A catch-all route

app/docs/[[...slug]]/page.tsx
import type { GetStaticPaths, PageProps } from '@gio.js/core';

export default function Doc({ params }: PageProps<'/docs/*slug?'>) {
  return <h1>{params.slug === '' ? 'Docs' : params.slug}</h1>;
}

export const getStaticPaths: GetStaticPaths<'/docs/*slug?'> = () => ({
  paths: [
    { params: { slug: [] } },                    // /docs
    { params: { slug: 'intro' } },               // /docs/intro
    { params: { slug: ['guides', 'setup'] } },   // /docs/guides/setup
  ],
});

Run the export; its summary lists every page written and every entry skipped:

npx gio export
text
[giojs] rendered 3 page(s):
   ✓ /docs
   ✓ /docs/guides/setup
   ✓ /docs/intro

Good to know

  • There is no fallback: a path that was not listed does not exist on the static host, which serves the exported 404.html.
  • Pages with no dynamic segment need no getStaticPaths; they are exported once.
  • The data is frozen at export time: re-run gio export to publish new posts.
  • getStaticPaths and the modules only it imports are left out of the browser bundle.
  • Exported pages carry their getServerSideProps props as JSON for hydration, so never return secrets from it.

Version history

VersionChanges
v0.1.0-beta.8Catch-all and optional catch-all routes, with strings or segment arrays; invalid entries are skipped with a reason; nothing is written outside out/; typed with GetStaticPaths.
v0.1.0-beta.5Removed from browser bundles, with the modules only it imports.
v0.1.0-beta.2Introduced, with gio export.