I’ve been building applications using Next.js for quite some time, and I’m consistently amazed by the developer experience it provides. It’s very easy to build a highly performant server-side-rendered (SSR) application using Next.js.
In version 9.3, Next introduced some amazing features, including:
- Next-gen static site generation (SSG) support
- Preview mode
- Built-in Sass support for global stylesheets
- Built-in Sass CSS module support for component-level styles
- And several others
In this post, we’ll mostly discuss next-gen SSG support and why integrating your Next.js app with Prisma makes this feature even more powerful. All the code snippets present in this article are available on GitHub.
Why use Prisma with Next.js?
Prisma is an open-source database toolkit. It helps us in querying our database by providing a type-safe API. Prisma Client is an auto-generated query builder that provides type-safe access to our database.
Integrating Prisma with Next.js
Integrating Prisma Client with Next.js is very easy. We need to install the dependency first:
yarn add @prisma/client
Next, we’ll need to initialize Prisma. Run the following command from the project root:
npx prisma init
This will generate the following files:

schema.prisma
– the Prisma schema with our database connection and the Prisma Client generator.env
– a dotenv file for defining environment variables (used for our database connection)
We’ll be using SQLite in our application, so let’s modify our .env
file:
// prisma/.env DATABASE_URL="file:./dev.db"
Let’s also modify our schema file to add two models:
- Post
id
title
content
published
author
authorId
- User
id
email
name
posts
// prisma/schema.prisma datasource db { provider = "sqlite" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model Post { id Int @id @default(autoincrement()) title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: [id]) authorId Int? } model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] }
Next, we need to migrate our database. To do that, we’ll run the following command:
npx prisma migrate save --experimental && npx prisma migrate up --experimental
Now, our Prisma directory will look like the following:

Next, we need to generate our Prisma client. We can do so with the following command:
npx prisma generate
Please note that we need to run the prisma generate
command after we change our Prisma schema to update the generated Prisma Client code. Also, prisma generate
is automatically invoked when we install the @prisma/client
npm module.
Now we can use Prisma in our code like the following:
// pages/get-static-props/index.js import { PrismaClient } from "@prisma/client"; import { Stack, Box, Link } from "@chakra-ui/core"; import _Link from "next/link"; const IndexPage = ({ posts }) => { return ( <Stack spacing={4}> {posts.map((post) => { return ( <Box key={post.id}> <_Link href="/get-static-props/[postId]" as={`/get-static-props/${post.id}`} > <Link>{post.title}</Link> </_Link> </Box> ); })} </Stack> ); }; export async function getStaticProps() { const prisma = new PrismaClient(); const posts = await prisma.post.findMany(); return { props: { posts, }, }; } export default IndexPage;
We can view our data through the Prisma Studio using the following command:
npx prisma studio --experimental
If we now visit http://localhost:5555/
, we should be able to view the Studio.

From here, we can manage the data through this interface.
What is static site generation?
When building web applications, we can choose to make our application generate statically or render it on the server side.
Before the release of version 9.3, any applications built with Next.js could opt into automatic static optimization. Any page that doesn’t have a blocking request using getInitialProps
would be optimized automatically, and the page would be rendered as static HTML.
However, it wasn’t possible to generate static pages for dynamic routes. With getStaticProps
and getServerSideProps
, it’s now possible to do SSG using Next.js.
getStaticProps
If we export an async
function called getStaticProps
, Next.js will fetch the data for this page during build time and store it as JSON inside the page. This is useful when we want to render static pages while fetching data from an API.
For example, if we define a getStaticProps
async function inside a page, it can fetch the data during build time and send that data to the component as props.
// pages/get-static-props/index.js export async function getStaticProps() { const prisma = new PrismaClient(); const posts = await prisma.post.findMany({ include: { author: true }, }); return { props: { // This will be sent to the component as props posts, }, }; }
In the component, we can access the posts
data as a prop:
// pages/get-static-props/index.js const GetStaticPropsIndexPage = ({ posts }) => { return ( <Stack spacing={4}> {posts.map((post) => { return ( <Box key={post.id}> <Heading mb={4} size="md"> {post.title} </Heading> </Box> ); })} </Stack> ); };
The above will render the content as expected:

getStaticProps
will generate the following JSON during build time:

Now, if we visit http://localhost:3000/get-static-props/1
, we’ll see the following page:

To view this page, we’ll have to add another async
function called getStaticPaths
:
// pages/get-static-props/[postId].js export async function getStaticProps(ctx) { const prisma = new PrismaClient(); const post = await prisma.post.findOne({ where: { id: parseInt(ctx.params.postId), }, }); return { props: { post, }, }; } export async function getStaticPaths() { return { paths: [{ params: { postId: "1" } }], fallback: false, }; }
Next.js will statically generate /1
at build time using the page component in pages/get-static-props/[postId].js
. If we now visit http://localhost:3000/get-static-props/1
and refresh the page, we’re able to view the page. However, if we do the same for http://localhost:3000/get-static-props/2
, we’d get a 404.
To solve this issue, we need to add the postId 2
as well to the paths
array:
paths: [{ params: { postId: "1" } }, { params: { postId: "2" } }],
Now, the http://localhost:3000/get-static-props/2
page will load fine.
getServerSideProps
If we export an async
function called getServerSideProps
in a page, Next.js will pre-render the page on each request using the data returned by getServerSideProps
. getServerSideProps
gets called every time we load the page, but the code is only executed on the server, unlike getInitialProps
.
// pages/get-server-side-props/index.js export async function getServerSideProps() { const prisma = new PrismaClient(); const posts = await prisma.post.findMany(); return { props: { posts, }, }; }
We can also fetch individual posts at http://localhost:3000/get-server-side-props/1:
// pages/get-server-side-props/index.js export async function getServerSideProps(ctx) { const prisma = new PrismaClient(); const post = await prisma.post.findOne({ where: { id: parseInt(ctx.params.postId), }, }); return { props: { post, }, }; }
Conclusion
In this post, we learned about how to make our Next.js applications faster using advanced features like getStaticProps
, getServerSideProps
, and Prisma. Until now, we’ve used getInitialProps
, which would make the page pre-render. However, any subsequent page redirects will fetch on the client side to get the new data.
With getServerSideProps
, every time the data will be fetched on the server, even on page redirects. With getStaticProps
, the data is fetched at build time; it won’t be called on the client side. As a result, the SSG page becomes very fast.