DEV Community

Cover image for Understanding next.js routing
Igor Petrovic
Igor Petrovic

Posted on • Updated on

Understanding next.js routing

This article is a quick introduction to next.js routing where I explain the steps I took to understand it.

When you first create a NEXT.js app with

npx create-next-app
Enter fullscreen mode Exit fullscreen mode

The file structure looks like this:

file structure 1

the pages folder contains the page which will be rendered.

Let's add a simple page contact.js

file structure 2

contact.js

export default function Contact() {
    return (
        <div>
            <h1>Contact page</h1>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

open http://localhost:3000/contact
and you should see your page title

contact page

Creating a large number of pages manually becomes quickly cumbersome. Fortunately NEXT.js provides dynamic routes.

Dynamic Routes

A dynamic route is basically a javascript file under pages/ folder with special characters in its name.

basis examples

  • [id].js
  • [slug].js
  • [user_id].js
  • [name].js

catch all examples

  • [...id].js
  • [...slug].js
  • [...user_id].js
  • [...name].js

Let's create a dynamic route.

dynamic-route-part-1

[slug].js

export default function DynamicPage() {
  return (
    <div>
      <p>dynamic page</p>
    </div>
  );
}

export async function getStaticPaths() {
  const posts = ["post/a", "post/b"];
  const paths = posts.map((post) => ({
    params: { slug: post },
  }));

  // { fallback: false } means other routes should 404.
  return { paths, fallback: false };
}
Enter fullscreen mode Exit fullscreen mode

When you navigate to this page you get a 404 error page.

post-a-not-found

Seems legit since the folder structure pages/[slug].js tells next.js that the path to these pages is at the root of the site. Something like /my-page should work. right ?

Let's navigate to /a. And then you get this error.

Error: getStaticPaths was added without a getStaticProps in /[slug]. Without getStaticProps, getStaticPaths does nothing
Enter fullscreen mode Exit fullscreen mode

error 1

reproduction repo

Let's add a getStaticProps

[slug].js

export default function DynamicPage(props) {
  return (
    <div>
      <p>dynamic page</p>
      <p>{props.message}</p>
    </div>
  );
}

export async function getStaticProps(context) {
  return {
    props: { message: "dynamic page part 2" }, // will be passed to the page component as props
  };
}

export async function getStaticPaths() {
  const posts = ["post/a", "post/b"];
  const paths = posts.map((post) => ({
    params: { slug: post },
  }));

  return { paths, fallback: false };
}
Enter fullscreen mode Exit fullscreen mode

The error is gone but the page is still not found.

/a not found

reproduction repo

Fix: [slug].js

You need to add the page a in getStaticPaths

[slug].js

export async function getStaticPaths() {
  const posts = ["post/a", "post/b", "a"];
  const paths = posts.map((post) => ({
    params: { slug: post },
  }));

  return { paths, fallback: false };
}
Enter fullscreen mode Exit fullscreen mode

a to getStaticPaths

And it works

/a works

But /post/a is still not found.

Fix: /post/a

Remember that next.js routing is based on the folder and files structure. For /post/a to work we need to create one of these files:

  • pages/post/a.js
  • pages/post/[slug].js
  • pages/post/[id].js

The examples use slug and id but you can actually use any name since next.js use file structure to map the url path.

file structure 3

This file structure tells next.js to render pages if an http client requests one of the following path:

  • /a
  • /post/a
  • /post/b
  • /post/c
  • /post/d
  • ...

Any path starting with /post/ becomes a valid path.

  • /post/a path will be rendered using pages/post/a.js
  • /post/<any> path will be rendered using pages/post/[slug].js

At this point, in pages/[slug].js paths post/a, post/b become irrelevant. We can delete them.

delete irrelevant

reproduction repo

Let's assume you have only two posts a and b

You don't want to render a page for non existing posts. To achieve this, you need to add getStaticPaths AND getStaticProps to file pages/post/[slug].js

pages/post/[slug].js

export default function DynamicPage(props) {
  return (
    <div>
      <p>dynamic page </p>
    </div>
  );
}
export async function getStaticProps(context) {
  return {
    props: { message: "some post" }, 
  };
}

export async function getStaticPaths() {
  const posts = ["a", "b"]; // <= the magic happens here
  const paths = posts.map((post) => ({
    params: { slug: post },
  }));

  return { paths, fallback: false };
}
Enter fullscreen mode Exit fullscreen mode

limit paths

This limits the valid url paths to:

  • /post/a
  • /post/b

reproduction repo

IMPORTANT

When you use getStaticPaths the paths params must match the filename.

This will throw an error.

match filename with path param

Error

Error: A required parameter (id) was not provided as a string in getStaticPaths for /post/[id]
Enter fullscreen mode Exit fullscreen mode

error 2

documentation

official doc

Latest comments (1)

Collapse
 
tutkun profile image
Samet Tutkun • Edited

Hey Igor, thank you for this share. I have a question, please can you help me?
I have a directory structure like this:

/pages/branches/[slug].tsx
/pages/branches/index.tsx
/pages/treatments/[slug].tsx
/pages/treatments/index.tsx
Enter fullscreen mode Exit fullscreen mode

However, I am using i18n for the multilingual feature. And this creates a false path. For example in browser url:

/en/branches/some-one-slug
Enter fullscreen mode Exit fullscreen mode

This is corrupting the directory path. Should I fix this in the next.config.js file? Can you recommend any content that can be a guide?