next.js: Unexpected behavior when using output: 'export', generateStaticParams(), and export const dynamic

Link to the code that reproduces this issue

https://codesandbox.io/p/sandbox/sweet-morning-nl3spx

To Reproduce

  1. Set output: 'export' in next.config.js
  2. Use generateStaticParams() in a Dynamic Route
  3. set export const dynamicParams = false and/or export const dynamic = 'force-static'
  4. Run next dev and attempt to visit a page on the dynamic route

Current vs. Expected behavior

Expected behavior:

Ignore the Route Segment Config options and/or generate a warning about them not being compatible.

Actual behavior:

Everything works correctly as long as you don’t use output: ‘export’ and dynamic/dynamicParams together.

When they are, the following error is sent: Error: Page "/[[...slug]]/page" is missing exported function "generateStaticParams()", which is required with "output: export" config. The page is obviously not missing the function as it’s right there and works fine under different configurations. This error occurs with all three types of Dynamic Routes when the Route Segment Configs are present with output: export. (Note: I have only tested with dynamic and dynamicParams so far.

If you take either of those conditions out, everything works as expected:

  • Without the output: export option, it will properly serve 404s when visiting a route that isn’t generated.
  • Without the route segment config
    • visiting a generated param results in a proper site render
    • visiting a non-generated param results in an error saying the route must be generated due to output: export
  • With or without the route segment config, next build will export a valid configuration by generating HTML pages for each output of generateStaticParams.

The errors only actually happen in next dev when both of the aforementioned conditions are present.

This scenario probably just warrants updated documentation and maybe extra sanity checks.

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

yarn next info
yarn next info
yarn run v1.22.19
$ /project/home/yukigamine/workspace/node_modules/.bin/next info

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
Binaries:
  Node: 16.17.0
  npm: 8.15.0
  Yarn: 1.22.19
  pnpm: 7.1.0
Relevant Packages:
  next: 13.5.4-canary.8
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.1.3
Next.js Config:
  output: export


Done in 1.62s.

Which area(s) are affected? (Select all that apply)

App Router, Routing (next/router, next/navigation, next/link), Static HTML Export (output: “export”)

Additional context

During testing, I went back to 13.4.19 and did not receive the error about generateStaticParams() missing under the circumstances described in this big report. I have not yet had a chance to look into whether the error just didn’t exist yet or simply wasn’t being thrown in that version, but it did entirely ignore the Route Segment Config options.

EDIT: For those looking for a workaround–

Rather than downgrading, simply remove export const dynamicParams = false and/or export const dynamic = 'force-static' from your file. These lines don’t actually do anything in output: 'export' and just cause next dev to get confused.

About this issue

  • Original URL
  • State: open
  • Created 9 months ago
  • Reactions: 39
  • Comments: 43

Commits related to this issue

Most upvoted comments

I confirm. Rolling back to 13.4.19 fixed it.

So… what are we supposed to do differently to support dynamic params with output:"export"??

I may be wrong, but I don’t think you can. The idea of output: "export" is is you are generating an entirely static site; the web server is not supposed to be doing anything other than serving files. If you have routes that are constantly changing, you need to be deploying Next.js using its node server, not exporting a static site.

image

app router i18n It’s a very common need.

I confirm. Rolling back to 13.4.19 fixed it.

@wdavidw I ended up sticking on the latest version but remove the dynamic and dynamicParams options because they don’t apply when you have output: export set.

If you have your generateStaticParams() function set up properly, everything works without those two options.

I think I’m in same situation as @jadsonlourenco : I’m using export for a pure client-side application, and just trying to use dynamic segments which will fetch data that relies on the segment data.

Per @Yukigamine 's comment:

You need to add a generateStaticParams() function if you’re going to use dynamic routes and output: “export”.

OK, but the docs actually say:

The generateStaticParams function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.

That’s exactly what I do not want to do. I don’t want to memoize the params, nor pre-compile routes with them at build-time, as these are data-driven params which change constantly. Docs for generateStaticParams() do not mention this use-case at all, nor use of output:"export".

So… what are we supposed to do differently to support dynamic params with output:"export"?? <He asks with gratitude and perspective, but also confusion.>

@xml

This has always been how nextjs has behaved since basically v1.

if you want runtime url parameters for a statically exported nextjs site you need to use either:

  • UrlFragment
  • UrlSearchParams

But just use UrlFragments, because:

  1. you don’t have anything server side that will affect the response of your exported html/js/css
  2. all your exported files should be cache busting fingerprinted anyway.
  3. your webserver should have caching rules to never cache html page response but always cache js/css files forever.
  4. so why bother sending query string params?
  5. urlfragments aren’t sent with browser requests
  6. so you won’t accidentally leak secrets or sensitive data to interim internet nodes between your sever and the user.
  7. you can still put http://ser.ver/some/page#?id=something&something=something&darkside which can be read by use-hash-param

edit: downvoters can QQ all you want. you need to understand what is possible in export mode. Furthermore, storing stuff like http://mysite.com/login?authtoken=abc123 is just asking to be the next haveibeenpwnd case.

Same problem on next 13.5.4

image image

Same problem on next 14.1.0

What should i do if i want to write code like this

export default function StudyMaterialItemPage({params}:{params:{id:string}}) { console.log(params); return <></> }

folder structure: study-materials/[id]/page.tsx

in next.config.js: output: ‘export’

but getting error: Error: Page “/(userPages)/study-materials/[id]/page” is missing exported function “generateStaticParams()”, which is required with “output: export” config.

The error is telling you exactly what is wrong. You need to add a generateStaticParams() function if you’re going to use dynamic routes and output: "export".

Best option right now is to downgrade next to 13.4.19. Hope this bug is fixed soon in the newer versions

There is no need to downgrade. Simply omitting or commenting out the lines with export const dynamicParams and/or export const dynamic should allow your generateStaticParams() function to work again. I’d barely call this a bug. It’s more of a documentation issue with unclear error messages.

I confirm. Rolling back to 13.4.19 fixed it.

@wdavidw I ended up sticking on the latest version but remove the dynamic and dynamicParams options because they don’t apply when you have output: export set. If you have your generateStaticParams() function set up properly, everything works without those two options.

Without dynamic = 'force-static' / dynamic = false, I don’t get 404 when I visit a non-existing generated page (eg /non-existent). But it actually shows a page and passes the param (non-existent)

(Works fine after building and served)

That was what initially confused me because next dev was handling the dynamic routes that wouldn’t actually be there during a build/export. So I added dynamic = 'force-static' / dynamic = false thinking I needed those too and then ran into this issue. Those two config options aren’t needed when you actually export, but I feel like they should be implied or automatically activated so that next dev shows the same behavior you’ll see when the site is statically exported.

But at the very least, the documentation should probably be updated so this situation is avoided or is less confusing.

PSA to everyone who downgraded, you can run the latest version of Next.JS, you just need to take out the dynamic = 'force-static' / dynamic = false options when running output: 'export'.

I think I’m in same situation as @jadsonlourenco : I’m using export for a pure client-side application, and just trying to use dynamic segments which will fetch data that relies on the segment data.

Per @Yukigamine 's comment:

You need to add a generateStaticParams() function if you’re going to use dynamic routes and output: “export”.

OK, but the docs actually say:

The generateStaticParams function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.

That’s exactly what I do not want to do. I don’t want to memoize the params, nor pre-compile routes with them at build-time, as these are data-driven params which change constantly. Docs for generateStaticParams() do not mention this use-case at all, nor use of output:"export".

So… what are we supposed to do differently to support dynamic params with output:"export"?? <He asks with gratitude and perspective, but also confusion.>

Yes, same bug when using “export” (v.14.0.3), dynamic route don’t work. My system is client side only, so, the “fetch” works after the user sign in, so, I can get the “slug” of the router and fetch the data.

Temp solution: downgrade to version 13.4.19

EDIT: I’ve upgraded to new version again because the “13.4.19” has bugs. So, the solution now is don’t use the “dynamic routes”, use the “searchParams”…

Same problem. Downgrade works for me.

It looks like 14 fails if generateStaticParams returns an empty array, in 13 this was accepted.

Same problem. Downgrade works for me.

can any one tell me why still have this issue in Nextjs 14 , this is my code for user page `// pages/users/[id]/page.js

import axios from ‘axios’;

export async function generateStaticParams() { const api = https://jsonplaceholder.typicode.com/users; const { data } = await axios.get(api);

// Generate static paths based on fetched data
const paths = data.map((user) => ({
    params: { id: user.id.toString() },
}));

return paths;

}

const Page = async ({ params }) => { const api = https://jsonplaceholder.typicode.com/users/${params.id}; const { data } = await axios.get(api); return ( <>

User Details

Name: {data.name}

Email: {data.email}

</> ); }; export default Page;

`

You should return the params directly, not an object with a params keys

In my case, this error was caused by my static parameters function not returning the proper type–typo in the object value.

https://nextjs.org/docs/app/api-reference/functions/generate-static-params#returns

I encountered the same issue recently with the latest version (14.1.0), but I managed to resolve it after realizing it was due to a careless mistake on my part. The error wasn’t because the expected exported function couldn’t be found, but rather because no valid params were being returned from the function.

Here’s a brief overview of my initial setup and the subsequent fix that resolved the issue:

Before the Fix:

type Params = {
  id: string;
}

type Props = {
  params: Params;
}

export default function Page(props: Props) {
  return <div>{props.params.id}</div>;
}

export const dynamicParams = false;

export const generateStaticParams = (): Props[] =>
  contentList.map((post) => ({ params: { id: post.id }}));

In this setup, generateStaticParams was supposed to export an array of Props, but it was actually expected to return an array of Params.

After the Fix:

type Params = {
  id: string;
}

type Props = {
  params: Params;
}

export default function Page(props: Props) {
  return <div>{props.params.id}</div>;
}

export const dynamicParams = false;

export const generateStaticParams = (): Params[] =>
  contentList.map((post) => ({ id: post.id }));

By changing the return type of generateStaticParams to an array of Params instead of Props, the issue was resolved. It appears the error was misleading, suggesting a missing function, when the real issue was with the type of data being returned.

I hope this helps anyone else facing the same or a similar problem!

Okay then,where/how can I catch these errors and manually redirect to a custom 404 page?

If you make a custom not-found using the built-in Next.js features, it will generate a 404.html file upon export. Then it’s up to you to configure the webserver to send them there.

I confirm. Rolling back to 13.4.19 fixed it.

@wdavidw I ended up sticking on the latest version but remove the dynamic and dynamicParams options because they don’t apply when you have output: export set. If you have your generateStaticParams() function set up properly, everything works without those two options.

Can i Have more details how to do this ? I feel Like I missed up

@bllfoad Have a look at how I update the source code in “page.js” of the TDP Website.

I confirm. Rolling back to 13.4.19 fixed it.

@wdavidw I ended up sticking on the latest version but remove the dynamic and dynamicParams options because they don’t apply when you have output: export set.

If you have your generateStaticParams() function set up properly, everything works without those two options.

Can i Have more details how to do this ? I feel Like I missed up

Downgrading to next 13.4.19 fixed it, but I’m not getting loaded correctly my js and CSS files

EDITL I fixed it adding assetPrefix: './’ in next.config.js

For me, the @Yukigamine solution works, thank you so much!

same problem for me

image