Dynamic route is not found in prod. it works fine on localhost

I’m trying to migrate my portfolio website (https://meje.dev) to use the recent version of Next.js and Typescript, plus a couple of improvements on my end too.

For my blog, I’m using next-mdx-remote and node’s filesystem module to read posts from my project.

When I run the dev server locally, and I click on a PostCard to view the article, the dynamic route renders my markdown content.

When I run the build locally too, it runs quite fine and completes the entire step without errors. But when I try to access any article in production, I’m met with a 404 page. I’m very confused, because this is almost the same thing (except the typescript migration) that powers the current website

Here’s the new site: https://sev-demo.vercel.app/

I’ve also tried adding a pageExtensions property to my nextConfig, but it’s still the same.

Here’s an excerpt of what my slug route looks like:

export type Post = {
  source: MDXRemoteSerializeResult<
    Record<string, unknown>,
    Record<string, unknown>
  >;
  tableOfContent: Heading;
  updatedAt: string;
  frontmatter: PostFrontmatter;
};

export default function BlogPost({ post }: { post: Post }) {
  return (
    <>
      <MetaData
        pageTitle={post.frontmatter.title}
      />
      <Layout>
        <Box display="flex" flexFlow="column" gap="1em">
          <Box className="content" pb="1.4em">
            <MDXRemote {...post.source} />
          </Box>
        </Box>
      </Layout>
    </>
  );
}

export async function getStaticProps(context: GetStaticPropsContext) {
  const slug = context?.params && context?.params.slug;

  const { content, frontmatter } = await getPostFromSlug(String(slug));
  const markdownHeadings = extractHeadings(`posts/${slug}.mdx`);
  const lastModified = await getLastModified(`posts/${slug}.mdx`);

  const posts = await getPosts();



  const rpcOptions = {
    theme: "aurora-x",
    keepBackground: false,
    defaultLang: {
      block: "javascript",
      inline: "plaintext",
    },
    filterMetaString: (str: string) => str.replace(/filename="[^"]*"/, ""),
  };

  const mdxSource = await serialize(content, {
    mdxOptions: {
      rehypePlugins: [
        rehypeSlug,
        [
          rehypeAutolinkHeadings,
          {
            properties: { className: ["anchor"] },
          },
          { behaviour: "wrap" },
        ],
        [rehypePrettyCode, rpcOptions],
        rehypeCodeTitles,
      ],
    },
  });

  return {
    props: {
      post: {
        frontmatter,
        source: mdxSource,
        tableOfContents: markdownHeadings,
        updatedAt: lastModified?.toDateString(),
      },
    },
  };
}

export async function getStaticPaths() {
  // prerender all pages
  // (slower builds, but faster initial page load)
  // const paths = (await getPostSlugs()).map((slug) => ({ params: { slug } }));

  return {
    paths: [],
    fallback: false,
  };
}

There’s another community post with 404 debugging tips that might be helpful. Please give these solutions a try and let us know how it goes.

A human should be around soon to offer more advice. But you can also get helpful information quickly by asking v0.

Hi @caleb335, thanks for posting your question here. It looks like you’re returning an empty paths array with fallback: false. The getStaticPaths function must return a list of paths when using fallback: false.

According to the docs:

If fallback is false , then any paths not returned by getStaticPaths will result in a 404 page .

This works on your local machine because Next.js will always render the page during development.

I’d recommend reading through the Data Fetching: Incremental Static Regeneration (ISR) | Next.js and the Data Fetching: getStaticPaths | Next.js documentation to understand how to implement your specific use case.

I hope this helps.

1 Like

oh! I have been receiving a prerender error before. that’s why I commented the paths variable. i ran the build locally now, and it passed.

It works in prod now, too. Many thanks!

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.