Get Started!

Next.js • Tailwind • Contentful Easy Starter

This page provides a complete guide on how to start a project using this starter.

Why

After so much time working with Contentful and Next, I never found a single consistent way of starting a project, and all starters that tried have their own caveats, some are too basic without touching the real problems like handling GraphQL query complexity limits or are too strict. I'm not saying this starter is better as there are many ways to accomplish the same thing when building with these technologies. Anyway, it was a lot of fun building it, exploring the nice features of React SSR inside Next.js, and playing with Contentful content modeling capabilities.

This project is the culmination of my own experimentations with Next.js and Contentful and it may not be suitable for your needs. If you are using it delete all Contentful contents as most are generated using AI tools like ChatGPT and DALL-E.

The tech stack

Key Decisions

  • Not just another starter, it's optioned in the way content models are shaped and how they are consumed in the FE.

  • Keep it simple but still powerful - like mentioned initially I wanted something that can be used in the real world and not another basic example.

  • Aware of limitations of using Contentful free tier - Limitations on the number of content models, locales, records, etc... are naturally applied. Being a hobby project and targetting personal websites I think the free tier makes all the sense, but bear in mind that if you want to use this for something more advanced I strongly recommend going with a paid tier.

    • Everything works with 20 content models (the limit on the free tier is 25).

    • Making content models suited for different cases (e.g. Hero can be used for 3 completely different hero components in the FE by using variant fields).

    • Implementation is aware of potential limits with GraphQL and deals accordingly with that.

  • Using DaisyUI for the sake of simplicity, but with the ability to change/extend the themes.

  • Flexibility in mind

  • Performance, on my tests the main pages I got a 99 on the homepage and 100 on the about page 🎊

lighthouse-about-page
Lighthouse score on the About page

Main Features

  • Flexible and composable content models

  • SEO ready with Metadata being generated based on specific SEO fields but with fallbacks in place

  • Generation of GraphQL (schema, and types), in sync with the content types via graphql-codegen.

  • Typescript

  • Tailwind CSS via DaisyUI

  • Nextjs SSR components

  • Contentful Live preview supporting inspector mode

  • Easy installation

Requirements

  • Access to a Contentful space (you can register for free here)

  • Optionally Turso DB is required for newsletter signups and article views counter.

  • An environment where you can run Node 18+

  • pnpm installed

Installation

  1. Clone the repo

  2. Install with pnpm

bash
1
2
3
4
5
6
7
8
9
10
11
git clone git@github.com:pauloamgomes/netcs.git
cd netcs
pnpm install

cp .env.example .env

# Grab your Contentful Space ID, Environment ID and Access Token and update the .env file
# CONTENTFUL_SPACE_ID=<your-space-id>
# CONTENTFUL_ENVIRONMENT_ID=<your-environment-id>
# CONTENTFUL_ACCESS_TOKEN=<your-access-token>
# CONTENTFUL_MANAGEMENT_TOKEN=<your-mgmt-token>

If you want to have article view counts and newsletter registration (optional)

  1. Create a Turso database

  2. Get an Auth token

  3. Place the Turso database url and auth token in your .env file

  4. Run the migration command and push the migrations

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# install and check installed version
brew install tursodatabase/tap/turso
turso --version

# signup/auth
turso auth signup # signup with github

# db creation
turso db create netcs-db # choose your own db name

# get db endpoint and auth token
turso db show netcs-db
db tokens create netcs-db 

# run and push the migrations
pnpm run db:generate
pnpm run db:push

# check on the Turso dashboard for your changes or run the editor locally
pnpm run db:studio

Better details regarding installing Turso in https://docs.turso.tech/tutorials/get-started-turso-cli/

Import example Data into Contentful

In order to be able to start the local server Contentful needs to have all content models created along with the example data, you can easily do it using the command contentful:seed

pnpm run contentful:import

The above command will import all example data you can see in this example website in your space.

Please note that the migration data is using a default Contentful locale en-US, if you want a different locale you'll need to manipulate the exported data by replacing in the migration JSON file all keys containing en-US.

Start Local server

If you did all the previous steps without errors and you feel courageous you can try to start the local server by running:

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
pnpm run dev

# and you should receive

> graphql-codegen --config codegen.ts

✔ Parse Configuration
✔ Generate outputs
   ▲ Next.js 14.0.2
   - Local:        http://localhost:3000
   - Environments: .env

 ✓ Ready in 1113ms

And voila, it works! 🎉

Configuring Live Preview

In order to use Contentful Live preview it's only required to set up a new Content Preview in Contentful:

Screenshot Live Prreview Config
Screenshot of example live preview configuration

If you are testing locally you can use a tool like ngrok to publicly expose your local server.

Content Models

Taking into consideration that this project should work using the Contentful free tier that is limited to 25 content models there are still a lot of possibilities, and you get:

Content Models
Content models used in the project - https://contentmodel.io/content-models/zb_NYSyloRr

The above diagram illustrates the defined content models for the project, there are some fundamental concepts:

  • A page content model to build flexible pages that are based on blocks

    • Everything that is prefixed with "Blocks" is to be used as building blocks for the page

  • Site settings to define site-wide definitions, like global SEO, main navigation, etc...

  • Navigation Link to allow the creation of navigation entries (e.g. for menus or CTA buttons) to internal pages or external URLs

  • Page hero - a global hero component with 3 variants (Background image, Side Image, or without image) and color and image mask customizations

Flexible Pages

I like the approach of having the freedom to create pages like building Lego blocks, therefore, that is trivial with Contentful:

Page Content Model
Screenshot of the page content model in Contentful

If you look at the homepage, the articles, or this page, they are built with that content model.

Blog Articles

If you have a blog on your website you can use the blog articles functionality, the content model in Contentful contains all typical information present in a blog article along with some extra bits, like the reading time being calculated by a Contentful app and having a visualization counter per article using Turso Database.

Article Detail Page
Screenshot of an example article page

Dashboard for visualizing stats on Article views

If the visualization counter for articles is enabled, the results can be checked inside Contentful in a simple Dashboard:

Article Views Dashboard
Dashboard with aggregated results per slug, country, browser, and device.
Article Views Table
Full view on all article visits.

Projects

If you have your own projects and want to display them on your website you can use the Project content model and create a page in Contentful using the projects template, automatically all projects will be listed.

Work Experience

You can create multiple experiences based on a time, company, and role and display information on the page. This is optional and it's up to you to create a work experience page.

Newsletter Registration

If you have your own newsletter you can have your website visitors register for it, for that, you only need to have a Turso Database, and from there, it is up to you how to sync the submissions from Turso to another system.

Newsletter Content Model
Screenshot of the newsletter block content entry in Contentful
newsletter form
Screenshot of the Newsletter form
Newsletter Submitted
Screenshot of a newsletter submission thank you message

Live Preview

Screencast showing live preview in action

Next.js Pages

Next.js is configured with some standard features.

Error Page

The default Next.js error page is customized to render an error page with the same website look and feel, including a retry button.

Screenshot Error Page
Screenshot of custom error page

404 Page

When accessing a non-existent page, a 404 error page will be rendered with the website's look and feel.

Screenshot Page 404
Screenshot of the 404 page screen

Sitemap and Robots

A sitemap.xml is automatically generated based on the Contentful contents, contents that contribute to a page (Page, Product, Work Experience, Blog Article) are fetched and populated in the sitemap.

Building Blocks

The project includes also a few components that are the foundation for assembling the pages or the article details page.

Accordions

Accordion is used for showing and hiding content

Accordions on webpages enhance user experience by organizing content into collapsible sections. They save space, simplify navigation, and allow users to focus on specific information, promoting a cleaner and more user-friendly interface.

Using DaisyUI accordions

Accordion uses the same style as the collapse component but it works with radio inputs. There are some changes to support multiple accordion items open at same time and they also support Images:

Cards

Cards are used in several places and defined in the Card component, they can be easily reused. Here is an example of using the card for rendering an article:

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Card as="li">
  <Card.Image
    url={image.url}
    alt={image.title}
  />
  <Card.Title href={getPageUrl(article)}>
    {article.title}
  </Card.Title>
  <Card.SubTitle className="text-xs justify-between">
    <span>{formatDate(article.publishedDate)}</span>
    <CategoryBadge
      category={
        article.categoriesCollection?.items?.[0] as Category
      }
      className="text-xs"
    />
  </Card.SubTitle>
  <Card.Description height="sm">{article.summary}</Card.Description>
  <Card.Cta>view more</Card.Cta>
</Card>

Code Block

The code block is useful to display code snippets, it depends on the Contentful Code Editor Field App and React Syntax Highlighter.

screenshot-code-block-entry
Screenshot of the Code block in Contentful
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// index.tsx

import React from 'react';
import Link from 'next/link';

const HomePage: React.FC = () => {
  return (
    <div>
      <h1>Welcome to Next.js!</h1>
      <nav>
        {/* Using Link for client-side navigation */}
        <Link href="/about">
          <a>About Page</a>
        </Link>
        <br />
        <Link href="/services">
          <a>Services Page</a>
        </Link>
      </nav>
    </div>
  );
};

export default HomePage;

Next.js navigation example between pages

Media

The Media block allows embedding videos from a video provider like Youtube or Vimeo or directly uploading in Contentful as an asset file.

screenshot-media-contentful
Screenshot of the Media entry

Example video - Tailwind Connect 2023

Information Message

An example of the Info Message with default Info Status

Another example of the Info Message with Warning Status

Another example of the Info Message with Success Status

Notifications

It's possible to configure global notifications that will be displayed as toast elements in the bottom right side of the screen and persist on the local storage.

screenshot-notificataions-contentful
Screenshot of the Site Settings entry - Notifications field
homepage-notifications
Screenshot of the notifications in action