Build pages from a data-source

from slugs to pages

The aim is to build pages from a data-source other than source-code files. The data source may be some local files or some data served by a remote server. We determine a list of pages, their content, where should they exist in the URL, and which React component they use.

pipeline overview

The pipeline runs at build-time. The whole process may be described as so:

  • We determine on which route the generated pages will live. We create a React file at the correct location in the file tree, and we give it a special name, such as [chapter].tsx to signal a special page.
  • We read the data-source to determine and register a list of slugs that we are about to make pages from. For example, we read a list of markdown files and determine a slug for each, and we register the list.
  • Then, we establish a data-gathering function that fetches data according to the provided slug, and returns it as a structured object. For example, it reads a markdown file and returns its content in a structured object.
    • Implementation detail: Such object has a props property, which itself is an object as well, and each property it holds is set to be given to the designated React component as a regular React prop.
  • Finally, we designate a React component to be used as a template, as it receives the gathered data and make use of it. It may notably set <title> in <Head> to ensure the generated page has an appropriate title.
  • Next.js ensures there is a fully-fledged HTML page for each slug.

determine the slugs

What is expected: an array of objects, each one representing a page. Each page comes with a params object. This object comes with one or more slugs. The single slug scenario is the most simple to reason about. We provide the slug as a property, whose name may be semantic or not, but the property name has to match the file, e.g. book for [book].tsx.

//  [
//    { params: { book: "typescript"}},
//    { params: { book: "javascript"}},
//    { params: { book: "clang"}}
//  ]

[book].tsx

export function getStaticPaths() {
    const books = getBooks()

    const paths = books.map((book) => ({
        params: { book: book.slug },
    }))

    return { paths, fallback: false }
}

gather data for a given slug

getStaticProps is expected to return this kind of structure:

// {
//     props: {
//         book: {
//             title: book.title,
//             slug: book.slug,
//             author: book.author,
//             lastUpdate: book.lastUpdate,
//         },
//     },
// )

[book].tsx

export async function getStaticProps({ params }: { params: { book: string } }): Promise<{
    props: BookUIProps
}> {
    const { book: bookSlug } = params
    const books = getBooks()
    const book = books.find((b) => b.slug === bookSlug)
    if (!book) {
        throw new Error(`Book not found: ${bookSlug}`)
    }
    const data = book.data // gather data here

    return {
        props: {
            book: {
                title: book.title,
                slug: book.slug,
                author: book.author,
                lastUpdate: book.lastUpdate,
            },
        },
    }
}

make use of the data

[book].tsx

export default function BookUI({ book }) {
    const { title, slug, author, lastUpdate } = book
    return <>{/*...*/}</>
}
earlymorning logo

© Antoine Weber 2026 - All rights reserved

Build pages from a data-source

from slugs to pages

The aim is to build pages from a data-source other than source-code files. The data source may be some local files or some data served by a remote server. We determine a list of pages, their content, where should they exist in the URL, and which React component they use.

pipeline overview

The pipeline runs at build-time. The whole process may be described as so:

  • We determine on which route the generated pages will live. We create a React file at the correct location in the file tree, and we give it a special name, such as [chapter].tsx to signal a special page.
  • We read the data-source to determine and register a list of slugs that we are about to make pages from. For example, we read a list of markdown files and determine a slug for each, and we register the list.
  • Then, we establish a data-gathering function that fetches data according to the provided slug, and returns it as a structured object. For example, it reads a markdown file and returns its content in a structured object.
    • Implementation detail: Such object has a props property, which itself is an object as well, and each property it holds is set to be given to the designated React component as a regular React prop.
  • Finally, we designate a React component to be used as a template, as it receives the gathered data and make use of it. It may notably set <title> in <Head> to ensure the generated page has an appropriate title.
  • Next.js ensures there is a fully-fledged HTML page for each slug.

determine the slugs

What is expected: an array of objects, each one representing a page. Each page comes with a params object. This object comes with one or more slugs. The single slug scenario is the most simple to reason about. We provide the slug as a property, whose name may be semantic or not, but the property name has to match the file, e.g. book for [book].tsx.

//  [
//    { params: { book: "typescript"}},
//    { params: { book: "javascript"}},
//    { params: { book: "clang"}}
//  ]

[book].tsx

export function getStaticPaths() {
    const books = getBooks()

    const paths = books.map((book) => ({
        params: { book: book.slug },
    }))

    return { paths, fallback: false }
}

gather data for a given slug

getStaticProps is expected to return this kind of structure:

// {
//     props: {
//         book: {
//             title: book.title,
//             slug: book.slug,
//             author: book.author,
//             lastUpdate: book.lastUpdate,
//         },
//     },
// )

[book].tsx

export async function getStaticProps({ params }: { params: { book: string } }): Promise<{
    props: BookUIProps
}> {
    const { book: bookSlug } = params
    const books = getBooks()
    const book = books.find((b) => b.slug === bookSlug)
    if (!book) {
        throw new Error(`Book not found: ${bookSlug}`)
    }
    const data = book.data // gather data here

    return {
        props: {
            book: {
                title: book.title,
                slug: book.slug,
                author: book.author,
                lastUpdate: book.lastUpdate,
            },
        },
    }
}

make use of the data

[book].tsx

export default function BookUI({ book }) {
    const { title, slug, author, lastUpdate } = book
    return <>{/*...*/}</>
}