Setting Up a NextJS DatoCMS Static Page
4 min read
Here's a step by step process for how to create a NextJS static page, that pulls in content from DatoCMS, at build time.
Step 1: Install packages
The packages I used included:
- react-datocms - A set of components and utilities to work faster with DatoCMS in React environments. Integrates seamlessly with DatoCMS's GraphQL Content Delivery API and Real-time Updates API.
- graphql-request - Minimal GraphQL client supporting Node and browsers for scripts or simple apps.
Step 2: Set up GraphQL client
Create a new file with a request
function that makes a GraphQL API call to DatoCMS. This is where you'll use the graphql-request
library. Replace process.env.DATOCMS_API_TOKEN
with your DatoCMS API token.
// datocms.ts
import { GraphQLClient } from 'graphql-request'
export function request({ query, variables }) {
const endpoint = 'https://graphql.datocms.com/'
const client = new GraphQLClient(endpoint, {
headers: {
authorization: `Bearer ${process.env.DATOCMS_API_TOKEN}`,
},
})
return client.request(query, variables)
}
Step 3: Structure GraphQL query
Assuming you've set up your blocks and content in DatoCMS, it's super easy to then structure the GraphQL query you need by using Dato's API Explorer. Upon choosing the fields you want to receive from your DatoCMS content database, copy and paste the query into a new file and save it to a constant.
At the bottom of the file, export an async function that awaits for the API response from the query you've just structured.
// Homepage.ts
import { HomePageRecord } from './types'
import { request } from './datocms'
const HOMEPAGE_QUERY = `
{
homePage {
heroSection {
headline: {
value: string
}
cta {
buttons {
__typename
id
buttonType
label
link
}
}
}
content {
__typename
... on ImageAndTextBlockRecord {
id
backgroundColour {
hex
}
}
// etc etc etc
}
}
}
`
export const getHomepageContent = async (): Promise<HomePageRecord> => {
const content = await request({
query: HOMEPAGE_QUERY,
variables: {},
})
return content.homePage
}
If you're using Typescript, here's an example of what the HomePageRecord
looks like.
export type ButtonRecord = {
__typename: 'ButtonRecord'
id: string
label: string
link: string
buttonType: 'primary' | 'secondary'
}
export type ButtonGroupRecord = {
__typename: 'ButtonGroupRecord'
id: string
buttons: ButtonRecord[]
}
export type HomePageHeroSection = {
cta: ButtonGroupRecord[]
headline: {
value: string
}
}
export type HomePageRecord = {
heroSection: HomePageHeroSection[]
content: Array<HomePageContentRecord>
}
Step 4: Create NextJS path
In the pages
directory, create the NextJS path where you want this DatoCMS content to be rendered. In this example, I wanted it to be the index page of the domain, so I created a new file in /pages/index.tsx
.
The logic in the file states that if the request returns a response that includes a heroSection
(required from the GraphQL query I structured), to send this response to the page component as props. If not, return a 404 page.
import { GetStaticProps } from 'next'
import { getHomepageContent } from '@/graphql/Homepage' // Homepage.ts file above
import { HomePage } from '@/components/HomePage' // new component to be created
export const getStaticProps: GetStaticProps = async () => {
const pageContent = await getHomepageContent()
if (pageContent?.heroSection) {
return {
props: {
pageContent: pageContent,
},
}
}
return {
notFound: true,
}
}
export default HomePage
Step 5: Create the page component
Finally, create the HomePage
page component that will be rendered when the above path is accessed. pageContent
is passed down within the props
per the above step.
import { Footer } from '@/components/elements/footer/Footer'
import { Header } from '@/components/elements/header/Header'
import { HomeContent } from '@/components/pages/home/HomeContent'
import { HomeHeroSection } from '@/components/pages/home/HomeHeroSection'
import { HomePageRecord } from './types' // defined in step 3
type HomePageProps = {
pageContent: HomePageRecord
}
export const HomePage: React.FC<HomePageProps> = ({ pageContent }) => {
return (
<>
<Header />
<main>
<HomeHeroSection content={pageContent.heroSection} />
<HomeContent content={pageContent.content} />
</main>
<Footer />
</>
)
}
If you're wondering where the need for the react-datocms
package comes in, it comes in handy when you actually get down to rendering DatoCMS blocks. For example, within the HomeHeroSection
component, I needed to render a structured text block (which contains rich text content). There's a component called StructuredText
that react-datocms
provides, which allows us to directly pass in the response object and render the rich text content with all the expected formatting.
import { StructuredText } from 'react-datocms'
import { HomePageHeroSection } from './types'
type HomeHeroSectionProps = {
content: HomePageHeroSection[]
}
export const HomeHeroSection = ({ content }: HomeHeroSectionProps) => {
return (
<StyledTextContent>
<StructuredText data={heroSection.headline} />
// ...other code bits here
</StyledTextContent>
)
}