Create a Next.js App with DatoCMS and Deploy It with Vercel

Deploy your Next.js and DatoCMS app with Vercel in a serverless environment.

This guide walks you through creating a blog using Next.js' Static Generation feature and DatoCMS through the DatoCMS GraphQL API and deploying the project with Vercel.

For the frontend of this project, you will be using Next.js – the production-ready React framework. For the backend you will be using DatoCMS – a powerful headless CMS that allows you to rapidly create, manage, and distribute content.

Two of the biggest selling points for DatoCMS are:

  • GraphQL API for powerful developer tools and complete control over the data your website downloads;
  • Out-of-the-box support to responsive, progressive, lazy-loaded images thanks to the fact that its GraphQL API already exposes pre-computed low-quality image placeholders (LQIP, or blur-up placeholders), allowing webpages to get everything they need in a single request, avoiding content reflows.

Preview of the website, complete with blur-up image placeholders.

Follow this guide to create a starting point for you to get your own blog up and running.

Step 1: Create your content

First, create an account on DatoCMS. After creating an account, create a new project from the dashboard. You can select a Blank Project. Once created, enter the project.

Create an Author model

Click the Settings tab, and choose the Models option. Click on the plus icon, and create a new Model called Author.

Next, add these fields (you don't have to modify the settings):

  • Name: field of type Single-line string (under the Text group)
  • Picture: field of type Single asset (under the Media group)

Follow these steps to create the Author model.

Create a Post model

Repeat the process to create a new model: this time call it Post.

Note: From the "Additional Settings" tab, turn on Enable draft/published system. This setting lets you preview the content.

Next, add these fields (you don't have to modify the settings unless specified):

  • Title: field of type Single-line string (under the Text group)
  • Content: field of type Multiple-paragraph text (under the Text group)
  • Excerpt: field of type Single-line string (under the Text group)
  • Cover image: field of type Single asset (under the Media group)
  • Date: field of type Date (under the Date and time group)
  • Author: field of type Single link (under the Links group). From the "Validations" tab under "Accept only specified model", select Author
  • Slug: field of type Slug (under the SEO group). From the "Validations" tab under "Reference field" select Title

Create a Blog model

The last model needed is called Blog. Make sure to check the "Single instance?" option for this, as you only want to create a single record of this type that will hold the SEO information for the blog page.

Next, add these fields (you don't have to modify the settings unless specified):

  • SEO: field of type SEO meta tags (under the SEO group)

Populate content

From the Content menu at the top, select Author and then create a new record. In this case, you can use dummy data for the text and download an image from Unsplash.

Follow these steps to populate your content.

Then create a couple of Post records. You can write markdown for the Content field, and for the Author you can pick one of the authors you created earlier.

Note: For each post record, you need to click Publish after saving. If not, the post will be in the draft state.

The last step is to fill in some SEO meta tags for your blog. Go to the Blog section, insert a title and a description and click "Save".

That's it for creating content! In general, you can edit both Content and Models at any time, giving you complete flexibility over your content.

Next, create a set of API tokens to be used in your app, these will allow the DatoCMS Client to request your posts from the DatoCMS API.

Step 2: Create a read-only API key

Click the Settings tab, and choose the API tokens option, then click on the plus icon to create a new API token.

Note: Make sure you only give the permissions to access the (read-only) Content Delivery API!

Follow these steps to create a read-only API Token for DatoCMS GraphQL API.

Make a note of the newly created access token, as it will be used later on.

That's all the setup required for DatoCMS! Within only a few minutes you have managed to create a Content Model, add content, and generate an API token.

Step 3: Create Your Next.js App

To display your new blog and content, create a new Next.js application using create-next-app, then run the following command and follow the wizard:

npm init next-app my-datocms-project

Bootstrap a Next.js application from your command line.

Enter inside the project directory, install the graphql-request and react-datocms package, and start the development server:

cd my-datocms-project && yarn add graphql-request react-datocms && yarn dev

Moving to your project, installing dependencies, and starting a local development server from the command line.

You'll need to setup a GraphQL client pointing to the API of your DatoCMS project. Create a new lib directory for that, and inside of it create a file called datocms.js:

import { GraphQLClient } from 'graphql-request'

export function request({ query, variables, preview }) {
  const endpoint = preview
    ? `https://graphql.datocms.com/preview`
    : `https://graphql.datocms.com/`

  const client = new GraphQLClient(endpoint, {
    headers: {
      authorization: `Bearer ${process.env.NEXT_DATOCMS_API_TOKEN}`
    }
  })
  return client.request(query, variables)
}

Creating a function in lib/datocms.js to get data from DatoCMS.

Using an environment variable starting with NEXT_ means that it will be automatically read by Next.js. Then, you can set the environment variable inside a .env file:

echo 'NEXT_DATOCMS_API_TOKEN=YOUR-API-TOKEN' >> .env

Creating an environment variable in a .env file for your API token.

Make sure that Git will ignore it by adding it to .gitignore:

echo '.env' >> .gitignore

Adding .env to the .gitignore file to avoid publishing to Git.

Next, go to pages/index.js — that is, the component that renders the homepage of the project — and replace its contents the following code:

import { request } from '../lib/datocms'
import { Image, renderMetaTags } from 'react-datocms'
import Head from 'next/head'

const HOMEPAGE_QUERY = `
query HomePage($limit: IntType) {
  site: _site {
    favicon: faviconMetaTags {
      attributes
      content
      tag
    }
  }
  blog {
    seo: _seoMetaTags {
      attributes
      content
      tag
    }
  }
  allPosts(first: $limit) {
    id
    title
    excerpt
    date
    author {
      name
    }
    coverImage {
      responsiveImage(imgixParams: { fit: crop, w: 300, h: 300, auto: format }) {
        srcSet
        webpSrcSet
        sizes
        src
        width
        height
        aspectRatio
        alt
        title
        base64
      }
    }
  }
}`

export async function getStaticProps() {
  const data = await request({
    query: HOMEPAGE_QUERY,
    variables: { limit: 10 }
  })

  return {
    props: {
      data
    }
  }
}

export default function Home({ data }) {
  return (
    <div>
      <Head>{renderMetaTags(data.blog.seo.concat(data.site.favicon))}</Head>
      {data.allPosts.map(blogPost => (
        <article key={blogPost.id}>
          <Image data={blogPost.coverImage.responsiveImage} />
          <h6>{blogPost.title}</h6>
        </article>
      ))}
    </div>
  )
}

An example Next.js index.js file for use with DatoCMS.

What the index.js Achieves

This index.js example requires the GraphQL client you created previously. Then, inside the getStaticProps function, a GraphQL request is performed, so that Next.js will pre-render this page at build time using the props returned by it.

The responsiveImage part of the GraphQL query returns image attributes that will help you set up responsive images in your frontend without any additional manipulation. The page component passes this data to the <Image/> component of the react-datocms package to render a lazy-loaded image with a low-quality image placeholder.

Similarly to what DatoCMS offers with responsive images, both the faviconMetaTags and _seoMetaTags parts of the query return pre-computed meta tags based on the content you insert inside DatoCMS. You can easily append such meta tags to the head of your page using Next.js's <Head/> component and the renderMetaTags helper, which is also part of the react-datocms package.

Note: The precise query to use depends on the models available in your specific DatoCMS project! You can learn everything you need regarding how to build GraphQL queries on DatoCMS's Content Delivery API documentation.

Setup Next.js Preview Mode

When using getStaticProps, the props will be generated at build time, which is great from a performance point of view, but not ideal when you’re writing a draft on DatoCMS. In this case, you want to preview the draft immediately on your page.

For solving that problem, Next.js has the feature called Preview Mode.

Create a preview API route

This API route file can have any name - e.g. pages/api/preview.js, thought it must be within the pages/api directory. In this API route, you will call setPreviewData on the response object. The argument for setPreviewData should be an object, and this can be used by getStaticProps (more on this later).

export default (req, res) => {
  res.setPreviewData({})
  res.writeHead(307, { Location: '/' })
  res.end()
}

The contents of a preview API route in Next.js.

To test this, manually access the route from your browser by heading to http://localhost:3000/api/preview. You’ll notice that you'll be redirected to the homepage with two cookies set: __prerender_bypass and __next_preview_data.

Update getStaticProps

The next step is to update getStaticProps to support the preview mode. If you request a page which has getStaticProps with the preview mode cookies set via res.setPreviewData, then getStaticProps will be called at request time instead of at build time.

Furthermore, it will be called with a context object where:

  • context.preview will be true.
  • context.previewData will be the same as the argument used for res.setPreviewData.

In this case, use the https://graphql.datocms.com/preview endpoint to access records at their latest version available, instead of only the currently published.

Both endpoints offer exactly the same queries, the only thing that will change will be the returned content:

export async function getStaticProps(context) {
  const data = await request({
    query: HOMEPAGE_QUERY,
    variables: { limit: 10 },
    preview: context.preview
  })

  return {
    props: { data }
  }
}

A Next.js getStaticProps function requesting preview content as specified in lib/datocms.js.

Note: The above code is a basic example. To learn more about Next.js Preview Mode and its security implications, take a look at the Next.js documentation.

Step 4: Deploy

Before deploying, make the DatoCMS API token available for your deployment, first add a vercel.json file at the root of your project directory with the following contents:

{
  "build": {
    "env": {
      "NEXT_DATOCMS_API_TOKEN": "@datocms_api_token"
    }
  }
}

An example vercel.json file for your Next.js + DatoCMS project.

Next, create a Secret using the Vercel CLI with the command below:

vercel secrets add datocms_api_token YOUR-API-TOKEN

Adding the datocms_api_token secret to your Vercel account using Secrets.

For a complete look at what you will deploy, see the example GitHub repository.

To deploy your Next.js + DatoCMS site with a Vercel for Git Integration, make sure it has been pushed to a Git repository.

Import the project into Vercel using your Git Integration of choice:

After your project has been imported, all subsequent pushes to branches will generate Preview Deployments, and all changes made to the default branch (commonly "master") will result in a Production Deployment.

Once deployed, you will get a URL to see your site live, such as the following: https://next-blog-datocms.now.sh/

Set up a Next.js + DatoCMS site with a few clicks using the Deploy button, and create a Git repository for it in the process for automatic deployments for your updates.



Written By
Written by stefanovernastefanoverna