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
⚡️Next.js 15 with App router
⚛️ React 19
💨 TailwindCSS + 🌻 DaisyUI
🗄️ Turso DB
👷Code on Github under the MIT License.
🌩️ Hosted on Vercel but be free to use a compatible hosting solution that you prefer
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 🎊
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
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
Clone the repo
Install with pnpm
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)
Create a Turso database
Get an Auth token
Place the Turso database url and auth token in your
.env
fileRun the migration command and push the migrations
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:
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:
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:
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:
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.
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:
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.
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.
404 Page
When accessing a non-existent page, a 404 error page will be rendered with the website's look and feel.
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
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.
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:
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.
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.
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.