View my Resume

How to Statically generate your dynamic pages in Nextjs 14

This is one topic I see a bunch on the web however, one note to this which I have note seen to much of is how to implement this within the app vs the pages router. Nextjs is a great framework for building fullstack React applications. It has a lot of features that make it easy to build and deploy applications. One of the features that I like the most is the ability to statically generate dynamic pages.

In this article, I will show you how to statically generate your dynamic pages in Nextjs 14 using the app router and using Supabase as my database of choice.

What is Static Generation?

Static Generation is the process of generating HTML files at build time. This means that the HTML files are generated once and served to the user without any further processing. This is great for performance because the HTML files are pre-generated and can be served quickly to the user.

Time to set up Dynamic Pages in Nextjs

To get started, you will need to create a new Nextjs project. You can do this by running the following command:

npx create-next-app@14 my-next-app

Next, you will need to install the Supabase client. You can do this by running the following command:

npm install @supabase/supabase-js

Next, you will need to create a new Supabase project. You can do this by going to the Supabase website and signing up for an account. Once you have created a new project, you will need to get the URL and the public key for your project.

Next, let's create a new directory structure at the root of app. You should have a file path app/lib/utils that will contain a file supabase.js (the reason for this abstraction is to mitigate any possibility of leaking a secret, even if they are behind a .env abstraction as well, which we'll talk about shortly). In this file, you will need to add the following code:

import { createClient } from '@supabase/supabase-js';
// You can get these values from your Supabase project
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_KEY;

export const supabase = createClient(supabaseUrl, supabaseKey);

Next, you will need to create a new directory structure at the root of app. You should have a file path app/pages/ideas/[slug]/ that will contain a file page.js. In this file, you will need to add the following code:

import { supabase } from '../../lib/utils/supabase';

export default function Idea({ idea }) {
return (
<div>
<h1>{idea.title}</h1>
<p>{idea.description}</p>
</div>
);
}

Next, you will need to add the following code to the to of the /[slug]/page.js file, just above the export default function Idea({ idea }):

export async function generateStaticParams() {
const { data: ideas } = await supabase.from('ideas').select('id')
return ideas?.map(({ id }) => ({
id: id.toString(),
}))
}

Next, you will need to update the export params to export default function Idea({ params: { slug }}), and add the following code to the Idea function just below the export default function Idea...:

const { data: post } = await supabase.from('posts').select().match({ slug }).single()

if (!post) {
notFound()
}

Note: The slug is the dynamic part of the URL that will be used to fetch the data from the database. In this case, the slug is the id of the idea for static generation, but in my example I have also made a slug field in the database to show how you can use a different field for the dynamic part of the URL.

Also, if you want to utilize the revalidate feature of Nextjs, you can add the following code above the page export:

export const revalidate = 60

Building the root Ideas page

Next, you will need to create a new directory structure at the root of app. You should have a file path app/pages/ideas/page.js which will live at the same level as the [slug] directory. In this file, you will need to add the following code:

import { supabase } from '../lib/utils/supabase';

export default function Ideas({ ideas }) {
const { data: ideas } = await supabase.from('ideas').select('*');
if (!ideas) {
return <p>No posts found.</p>
}

return (
<div>
<h1>Ideas</h1>
<ul>
{ideas.map((idea) => (
<li key={idea.id}>
<a href={`/ideas/${idea.id}`}>{idea.title}</a>
</li>
))}
</ul>
</div>
);
}

This will create a page that lists all the ideas in the database. You can then click on an idea to head to the dynamic page for that idea.

Time to build it!

Now that you have set up the dynamic pages in Nextjs, as well as the root ideas page, you can build the project by running the following command:

npm run build

If we set up everything correctly - this command will generate the static HTML files for the dynamic pages in the /ideas/[slug], show a filled in circle which will reference:

(SSG) prerendered as static HTML (uses getStaticProps)`

in the terminal output.

Conclusion

Hopefully this article has helped you to understand how to statically generate your dynamic pages in Nextjs 14 using the app router. This is a great feature that can help you to improve the performance of your application and provide a better user experience (especially if you are fetching data from a source like Supabase). Thanks for reading!!

Posted: April 3, 2024