Next.js Discord

Discord Forum

getStaticPaths vs getStaticProps vs generateStaticParams

Answered
Airedale Terrier posted this in #help-forum
Open in Discord
Airedale TerrierOP
Hi I am trying to understand when to use which method for generating dynamic routes. I have a notes taking app that renders staticaly generated web pages (export: true) with dynamic routes
I have two pages with dynamic routes :
pastelog/src/app/(main)/logs/[id]/page.tsx
pastelog/src/app/(publish)/logs/publish/[id] /page.tsx

fetchLogs is basically calling a method from firestore and fetching the document id, The app works fine, But I would like to integrate local Storgae, but as soon as I replace that method with fetching logs from local Storage I get the below error
⨯ Error: Page "/(main)/logs/[id]/page" is missing param "/logs/vCkOcmUZQdxA0muPBQTk" in "generateStaticParams()", which is required with "output: export" config.

My requirement is that when I publish a log it should be saved to both local and firebase and when fetched it should be fetched only from localStorage on routes with logs/id and from firebase on routes with logs/publish/id

I looked at the documentation from nextJS and it seems to suggest to use
getStaticPaths: if you’re statically pre-rendering pages that use dynamic routes and:

The data comes from a database

But, It also reads

getStaticPaths will only run during build in production, it will not be called during runtime.

Some guidance on what is the best choice for my requirement would be really helpful.
Thanks
Answered by Anay-208
So how its working is that, with out param
View full answer

145 Replies

Airedale TerrierOP
The code sample of those two dynamic routes

  import Preview from '@/app/(main)/_components/Preview';
    import type { Metadata } from "next";
    import LogService from '../../_services/logService';
    
    // This is required for dynamic routing in runtime
    export const dynamicParams = true;
    
    export const metadata: Metadata = {
        title: "Pastelog",
        description: "PasteLog is a simple, fast, and powerful pastebin. It is powered by firebase in the backend. It allows you to publish your logs, and access them from anywhere and any device via a unique link.",
    
    };
    export async function generateStaticParams() {
        const logService = new LogService();
        const logs = await logService.fetchLogs();
        return logs.map(log => ({ id: log.id }));
    }
    
    
    export default function LogPage({ params }: { params: { id: string } }) {
        const { id } = params;
        return <Preview
            logId={id}
        />;
    };

and

pastelog/src/app/(publish)/logs/publish/[id] /page.tsx
import Preview from '@/app/(main)/_components/Preview';
import LogService from '@/app/(main)/_services/logService';

// This is required for dynamic routing in runtime
export const dynamicParams = true;

export async function generateStaticParams() {
    const logService = new LogService();
    const logs = await logService.fetchLogs();
    return logs.map(log => ({ id: log.id }));
}
export default function PublishPage({ params }: { params: { id: string } }) {
    const { id } = params;
    return <Preview
        logId={id}
    />
};

This is the structure of the app
Don't mix-up old nextjs with new, staticPath and StaticProps is used in Pages directory, and generateStaticParams is used in App router.
In your case read generateStaticParams doc's and focus on it
Logs/publish/[id]
-> pages.tsx
In here return array of id objects you expect from db, fetch all the IDs. And put it and return it in an array.
Airedale TerrierOP
Thanks for the reply @muadpn
I found that the above error is because of this issue, I am getting
ReferenceError: localStorage is not defined

during dynamic segments routing hence the array is empty
export async function generateStaticParams() {
    const logService = new LogService();
    const l = localStorage.getItem('logs');
    console.log("fetchded during routing", l);
    // returns an empty array
    const logs = await logService.fetchLogsFromLocal();
    console.log(logs);
    return logs.map(log => ({ id: log.id }));
}
Airedale TerrierOP
My app is pretty simple i have a

sidebar and a main content
sidebar is a client component which is fetching list of logs from local (works fine)
when I select a list item I am redirecting to logs/id which is this code logs/[id]/page.tsx

It is not necessary that I have to use the data from local Storage, I am okay with using fetching data from server provided I have the ID available in the main content (preview component)
<Preview
            logId={id}
        />;)
Airedale TerrierOP
I am getting the errror only during navigation

This error is only during navigation and goes away on refreshing the browser

I have made a detailed post if anyone is interested to assist https://www.reddit.com/r/nextjs/comments/1di8ec9/error_page_is_missing_param_in/
Airedale TerrierOP
Yes I understand that I am calling fetchLogs() (from server) in generateStaticParams

please see the reddit link for the complete details
Well dude, you are trying to get firebase app on server which cannot be don, you need to initiate admin SDK for that
Those errors are shown because you are incorrectly sending params to the page. Either the data is invalid, and since firebase is client / browser the data won't be fetched at the server since there is no data it gives you error. This is to my point of view about firebase/next
Airedale TerrierOP
But fetchlogs in generateStaticParams is returning all the documents including the newly added document, attached is the structure of the document
Console log the data and check whether it's showing in terminal or the browser console.
Airedale TerrierOP
the console log of fetch logs is only in the terminal not in browser console
also when the error occurs refreshing the page the app works fine
Can you build it locally?
Airedale TerrierOP
Yes I am able to build and deploy using npm run build
You can check the issue at https://pastelog.web.app
Golden paper wasp
Can you share me the build log? How much pages are created, also can you delete .next and try to build again?
Airedale TerrierOP
sure, meanwhile the build runs, if you would like to see the actions log

https://github.com/maheshmnj/pastelog/actions/runs/9553678515/job/26333032686
Here is the complete attached logs
.next
Really weird, firebase client app supposed to run on client, not server. Anyway your issue is to implement static generation with local storage?.
Airedale TerrierOP
Yes
I am not sure what you mean by static generation?
My only requirement is to have published notes available at their own link just like a blogging post site has, the additional requirement is I am also storing those logs to local storage (client component) only to retrieve the ids in a sidebar
Can I get a summary of the current issue now
Airedale TerrierOP
Yes
I am seeing this error only during navigation

Error: Page "/(publish)/logs/publish/[id]/page" is missing param "/logs/publish/BrWyKK8oGhiSAnTrLDAX" in "generateStaticParams()", which is required with "output: export" config.


This is the folder structure of the app

root /
    ├──src
    │    ├── app /
    │    │    ├── (main)/
    │    │    │    ├── _models/
    │    │    │    │   ├── Log.ts
    │    │    │    ├── _services/
    │    │    │    │   ├── LogService.ts
    │    │    │    ├── _components/
    │    │    │    │   ├── Sidebar.tsx
    │    │    │    │   ├── Navbar.tsx
    │    │    │    │   ├── Pastelog.tsx
    │    │    │    │   │
    │    │    │    ├── logs /
    │    │    │    │   ├──[id]
    │    │    │    │   │   └── page.tsx
    │    │    │    │   └── layout.tsx
    │    │    │    │   └── page.tsx
    │    │    ├── (publish)/
    │    │    │    ├── logs /
    │    │    │    │   ├── publish /
    │    │    │    │   │    ├──[id]/
    │    │    │    │   │        └── page.tsx
    │    │    │    └── layout.tsx
    │    │    │
    │    │    └── layout.tsx
    │    │    └── global.css
    │    │    └── page.tsx
adding more
ya, you need to export a function getStaticParams
Airedale TerrierOP
I have a sidebar and a MainContent (Pastelog/Preview)

renders

Pastelog: at baseurl/logs
Preview: at baseurl/logs/[id]

- Sidebar is a client component which renders list of logs from local storage (works fine)
- Pastelog has a button to publish the logs and redirect to baseurl/logs/publish/id

When I hit publish I am saving the data to firestore and local storage and redirecting to dynamic route

(method to publish)
    async function publish() {
        setLoading(true);
        const log = new Log(
            expiryDate.toDate('UTC'),
            content,
            new Date(),
            LogType.TEXT,
            true,
            title,
            false,
        );
        const id = await logService.publishLog(log);
        if (!id) {
            setLoading(false);
            return;
        }
        router.push(`/logs/publish/${id}`);
        setLoading(false);
    }

The data is getting stored in both local storage and firestore but when I redirect to dynamic route I am seeing this error

Error: Page "/(publish)/logs/publish/[id]/page" is missing param "/logs/publish/BrWyKK8oGhiSAnTrLDAX" in "generateStaticParams()
// logs/publish/[id]/page.tsx
import Preview from '@/app/(main)/_components/Preview';
import LogService from '@/app/(main)/_services/logService';

// This is required for dynamic routing in runtime
export const dynamicParams = true;

export async function generateStaticParams() {
    const logService = new LogService();
    const logs = await logService.fetchLogs();
    // logs.forEach(log => console.log(log.id));
    return logs.map(log => ({ id: log.id }));
}
export default function PublishPage({ params }: { params: { id: string } }) {
    const { id } = params;
    return <Preview
        logId={id}
    />
};


This is the nextjs config

/** @type {import('next').NextConfig} */
const nextConfig = {
    output: 'export',
    trailingSlash: true,
    images: {
        unoptimized: true
    }
};

export default nextConfig;


This error is only during navigation and goes away on refreshing the browser
Can you provide a min repro repo?
Airedale TerrierOP
here is the repository (not minimal) https://github.com/maheshmnj/pastelog/tree/web/
but I think the code is fairly simple incase you need me to reduce the code further I can do that and get back
I'll look int this issue tonight when I get free
Airedale TerrierOP
reproduction guidelines here http://pastelog.web.app/logs/publish/A2IPVQ02ETXtsQ2qretK/

link will be active in next 5 mins
@Airedale Terrier reproduction guidelines here http://pastelog.web.app/logs/publish/A2IPVQ02ETXtsQ2qretK/ link will be active in next 5 mins
Airedale TerrierOP
This link is active now this link is of the same app where the issue is, Strangely this link works only in incognito
Airedale TerrierOP
@Anay-208 thanks for taking a look, page.tsx has generateStaticParams so we cannot use "use client"
I have created a minimal reproduction if you would like to take a look https://github.com/maheshmnj/pastelog/tree/routing/src/app
In dev version, what happens if you visit /logs/publish/BrWyKK8oGhiSAnTrLDAX
Airedale TerrierOP
it works the first time takes almost 7-10 secs to redirect, and when I go back (browser back button) publish again I see the error
@Airedale Terrier it works the first time takes almost 7-10 secs to redirect, and when I go back (browser back button) publish again I see the error
Can you share a screen recording of behaviour? I didn’t really get what you mean?
Airedale TerrierOP
sure
here you go
@Airedale Terrier here you go
Now stop the dev server. Then visit any log, then try publishing
If I’m right, it will fail
Airedale TerrierOP
This is in production (deployed app)
I'm currently talking about development only
I think I found the cause to the problem, but I need to verify
@Airedale Terrier here you go
First of all, Visit any log
Then try publishin
@Anay-208 Now stop the dev server. Then visit any log, then try publishing
Airedale TerrierOP
Stop the dev server and start again and visit any log?
yes
Then try publishing
Airedale TerrierOP
visit at logs/id?
or logs/publish/id
logs on the sidebar redirect at logs/id
Visit any published log
First
any published log, then try publishing
If I'm right, it'll fail
Airedale TerrierOP
So it failed
Airedale TerrierOP
yes
So how its working is that, with out param
Answer
So Whenever you visit the page, It first of all, gets all the log ids from the database
and it saves the content of the log
And if you try to visit the page again, It'll display whatever content it has
But It didn't find any content for that param
and thats resulting in an error
You can't use static build with this
Airedale TerrierOP
so what is other alternative apart from static build?
The normal build
Which you can deploy to vercel, cloudflare pages
@Anay-208 You can't use static build with this
And mark this message here
Airedale TerrierOP
what do you mean by out param ?
@Airedale Terrier what do you mean by out param ?
in next.config.js|ts, you've added
Airedale TerrierOP
you mean output:export?
when I remove that and do a normal build npm run build I don't see the out folder generating
yes
@Airedale Terrier you mean output:export?
You've added this, which results in a static build
You can remove that, and the issue will be fixed, and also remove generateStaticParams
And it should fix the issue
but you won't be able to use static build
Airedale TerrierOP
after removing output:export the dynamic page won't receive params right?

PublishPage({ params }

import Preview from '@/app/(main)/_components/Preview';
import LogService from '@/app/(main)/_services/logService';

// This is required for dynamic routing in runtime
export const dynamicParams = true;

// export async function generateStaticParams() {
//     const logService = new LogService();
//     const logs = await logService.fetchLogs();
//     return logs.map(log => ({ id: log.id }));
// }
export default function PublishPage({ params }: { params: { id: string } }) {
    const { id } = params;
    return <Preview
        logId={id}
    />
};
Yes
this should work now
try in development first
Airedale TerrierOP
Awesome this is working fine locally can't thank you enough
@Anay-208 You can't use static build with this
Can you mark this message as a solution?
Airedale TerrierOP
I would have loved to offer you a bounty on the stackoverflow, I was about to start a bounty
Airedale TerrierOP
You can do that yes
stackoverflow doesn't allow starting a bounty atleast two days after posting the question
Please add a detailed answer after I start a bounty
@Anay-208 You can't use static build with this
Alright, Can you mark this message as solution here?
By right clicking>Apps>Mark solution
Airedale TerrierOP
regarding generating a normal build
where are the output files generated to deploy?
And you’ll have to deploy it to Vercel, cf pages, or self host it
Airedale TerrierOP
However, I recommend google cloud run
If talking about services within google
I personally use cloudflare pages to deploy nextjs apps
Airedale TerrierOP
I would like to keep this free domain from firebase pastelog.web.app
I am not looking to pay for the services for this app at this time.
With google cloud run, you can also add domain to firebase
You can directly add a firebase domain to google cloud run
Airedale TerrierOP
Will take a look at that trying this for now

npm run build && npm run export && firebase deploy --only hosting
looks like export is for static sites in old version of nextjs
You've to use either app hosting or cloud run
Airedale TerrierOP
I deployed it to vercel and its working perfectly fine. https://pastelog.vercel.app/
I will notify you here once I start the bounty
Airedale TerrierOP
Does anyone know how to access env variables in cloud run? I added them to cloud run but looks like they are not accessible
Airedale TerrierOP
vercel takes care of it, this is the app in cloud run https://pastelog-d6s7zhnvha-uc.a.run.app/logs/
I found this solution which suggest using a dockerfile but looks like we will have to push the dockerfile to github that way the variables will be exposed
https://stackoverflow.com/a/67327550/8253662
Airedale TerrierOP
Is it possible to point the firebase domain to cloud run deployed app?
Click manage custom domain
and you can deploy with firebase
Airedale TerrierOP
tried this
not sure what is subdomain siteid
I used the one I found by running firebase hosting:sites:list
looks like it worked this time
Airedale TerrierOP
I realized that this error is because site with id 'pastelog' already exists I tried creating a new site with id pastelog-prod it worked need to figure out how to change the id
@Airedale Terrier can you start a bounty then?
Airedale TerrierOP
I started the bounty, Please add a clear answer and up vote the question too thanks
Posted @Airedale Terrier, I basically edited & undeleted prev one
let me know when done
Airedale TerrierOP
Thanks I will be able to award the bounty after 24 hours