How To Build A Blog With The Ghost API and Next - Js
How To Build A Blog With The Ghost API and Next - Js
js
Ghost CMS is a popular content management system that many devs and companies use to
host their blogs.
It has many features and an editor that's highly optimized for writing. You can even build
different themes using handlebars.js.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 1/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
But if you don't know Handlebars, learning it can be a long and difficult process. If you are
already a Next.js developer and you don't know Handlebars, creating a new theme for your
Ghost-based site can be tough.
In the article, I will teach you how to use Ghost CMS as a backend and Next.js as a frontend.
I will guide you through everything related to Nextjs 13 app directory and the Ghost CMS
API.
Next.js 13 team currently working on the experimental app folder. Next uses file-based
routing with the page directory. The new app directory is based on file system routing and
provides additional functionality like layouts, error handling, component loading, and server-
side and client-side rending out of the box.
All the code is available on GitHub. You can also check out the live demo website.
Table of Contents
In this article, we cover the basics of Next's experimental app directory. Then I'll teach you
how to step up Next and Ghost CMS locally and how to integrate Ghost with Next. Lastly, I'll
show you how to consume data from the backend (via theGhost CMS API ) and show it on
the site with React.js.
Why Use Next.js for the Front End and Not a Ghost CMS Theme?
There are a few reasons why you might consider using Next as the frontend framework for
your blog:
Basically, when it comes to static builds and website performance, Ghost doesn't perform as
well in either case. The alternative is to use a frontend platform like Next, React, Angular, or
Vue.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 2/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
I chose Next because it's a highly in-demand and popular React framework, and plenty of
tools and libraries are built around it.
Note that the current project is not ready for TypeScript, but I'm working on it. Because of this
I disabled TypeScript during build time like this:
typescript: {
ignoreBuildErrors: false,
},
module.exports = nextConfig
Project Requirements
To follow along with this tutorial, you'll need basic knowledge of the following packages:
1. PNPM is a Node.js package manager similar to npm or yarn (you can use any of them
that you prefer).
2. TypeScript helps you write type-safe code in JavaScript, and can also help improve
productivity. It is not required, though. You can use JavaScript in your project.
3. React.js is a free and open-source front-end JavaScript library for building user
interfaces with class and function components.
4. Next.js 13 (app) is based on React and it provides additional functionality like routing,
error handling, and layouts.
5. Ghost CMS API is an open-source content management system (CMS) similar to
WordPress. Ghost is specifically designed and built for blogging. In this project, we'll
Ghost as the backend and Next as the frontend. For communication between the
backend and frontend development, we'll use the Ghost CMS API.
6. Tailwind CSS is an open source CSS-based framework similar to Bootstrap. We'll use
Tailwind CSS to design our blog website.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 3/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
# or
# or
After installing the Ghost CLI, you can create a new Ghost blog project locally with the
following command:
After the blog installation is finished, you can start your local development server with the
ghost start command and your local development serve on
http://localhost:2368/ghost.
There are a few additional commands that are helpful when using the Ghost CLI:
Note:
Make sure your current installation directory is empty before installation. Currently, you are
installing Ghost in development mode. For production, you won't follow the same steps.
I like digital press because it comes with a free plan. Other cloud services do not provide
that, which is why I suggest it.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 4/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Here are the commands to run depending on whether you're using npx, yarn, or pnpm:
# or
# or
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 5/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
After completing the installation process, we must install some additional Node packages for
the blog.
These Node packages can help you speed up your development process. Make sure to
install all the below packages to follow along with this guide:
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 6/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Every video explains the same kind of topic. If you watch each of the four videos, you have a
basic idea of how the Next.js app folder works. That will make this advanced tutorial easier
to follow.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 7/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Vercel
In this tutorial, Lee Robinson covers the basics of routing, dynamic route segments, data
fetching, caching, and metadata.
Sakura Dev
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 8/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Tuomo Kankaanpaa
Tuomo Kankaanpaa teaches you about Next app folder routing, layouts, and server
components.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 9/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Piyush Garg
Piyush Garg compiles all the new Next features and converts them into a small crash
course, and builds a demo project.
Now that you're ready to go, let's get into building our blog.
Folder Structure
Our folder structure looks like this for our demo application:
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 10/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
.
├── next.config.js
├── next-env.d.ts
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
├── README.md
├── search.json
├── src
│ └── app
│ ├── authors
│ │ └── [slug]
│ │ └── page.tsx
│ ├── BlogLayout.tsx
│ ├── cards.min.css
│ ├── Card.tsx
│ ├── error.tsx
│ ├── favicon.ico
│ ├── Footer.tsx
│ ├── ghost-client.ts
│ ├── globals.css
│ ├── Header.tsx
│ ├── layout.tsx
│ ├── not-found.tsx
│ ├── pages
│ │ └── [slug]
│ │ └── page.tsx
│ ├── page.tsx
│ ├── pagination
│ │ └── [item]
│ │ └── page.tsx
│ ├── Pagination.tsx
│ ├── read
│ │ └── [slug]
│ │ ├── Newsletter.tsx
│ │ └── page.tsx
│ ├── Search.tsx
│ ├── SocialIcons.tsx
│ └── tags
│ └── [slug]
│ └── page.tsx
├── tailwind.config.js
└── tsconfig.json
13 directories, 30 files
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 11/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Ghost CMS comes with two types of APIs: the first is the Content API, and the second is the
Admin API. For the blog, we'll use the Content API.
Content API is a RESTful API that fetches the published content for the Ghost database. It is
a read-only API. You can not call POST requests with it.
To configure it, we create a new file inside the src/app folder with ghost-client.ts. Inside
the file, we have a new Ghost API instance.
// ghost-client.ts
We need the blog URL, key, and version to config the Ghost content API in Next. You can
find both the URLs and Key properties in the Ghost dashboard, as well as the version value
which is your current version of Ghost CMS.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 12/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Go to dashboard > settings > integrations > Your-intergration-id and get your
GHOST_URL and GHOST_KEY . Now you can copy both and paste them inside your .env.local
file.
Examples
To understand the Next experimental app folder, let's look at a real example:
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 13/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Now you can create five files inside every route. For example, if you create a tag or
category route in your app folder, then you can create four files inside your app route folder.
Let's understand how the new Next.js 13 app route works with a real-life example: your tag
route folder looks like this.
app/tag/[slug]/page.ts
app/tag/[slug]/loading.ts
app/tag/[slug]/layout.ts
app/tag/[slug]/error.ts
app/tag/[slug]/my-card-component.ts
First is the logo, next comes the nav bar with various elements, and last is the icon section.
All the data comes from the Ghost CMS API. You can change things inside Ghost CMS and
it will reflect on the site.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 14/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// Header.tsx
return (
<header className="px-2 sm:px-4 py-2.5 dark:bg-gray-900 w-full">
{
/* Blog Navigation Edit in GHOST CMS */
setting.navigation !== undefined ? setting?.navigation.map(item => <li
key={item.label} className="block py-2 pl-3 pr-4 text-gray-700 rounded hover:text-
blue-700 dark:hover:text-blue-700 md:p-0 dark:text-white"
aria-current="page">
<Link href={item.url}>
{item.label}
</Link>
</li>) : " "
</ul>
</div>
<SocialIcons setting={setting} />
</div>
</header >
)
}
export default Header
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 15/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
I designed a basic footer with copyrighted text and added social icons for the site. The social
icons come from the Ghost CMS API.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 16/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// Footer.tsx
return (
{
setting.twitter !== null ? <li>
<Link target="_blank" href={`https://twitter.com/${setting.twitter}`}
className="block py-2 pl-3 pr-4 text-gray-700 rounded hover:text-blue-700
dark:hover:text-blue-700 md:p-0 dark:text-white" aria-current="page">
<FaTwitter />
</Link>
</li> : " "
{
setting.facebook !== null ? <li>
<Link target="_blank" href=
{`https://www.facebook.com/${setting.facebook}`} className="block py-2 pl-3 pr-4
text-gray-700 rounded hover:text-blue-700 dark:hover:text-blue-700 md:p-0 dark:text-
white ">
<FaFacebook />
</Link>
</li> : " "
</ul>
</div>
</div>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 17/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
</footer>
)
}
I designed a basic layout for the blog. For building layouts in Next.js, there's a special
layout.tsx file.
Before we create the layout design, we need to define a getNavigation function to fetch
navigation and basic website-related data from Ghost.
// ghost-client.ts
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 18/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
{
title: 'Rajdeep Singh',
description: 'Thoughts, stories and ideas.',
logo: 'http://localhost:2368/content/images/2023/04/nextjsandghostlogo-2.png',
icon: 'http://localhost:2368/content/images/size/w256h256/2023/04/nextjs-
60pxx60px.png',
accent_color: '#d27fa0',
cover_image: 'https://static.ghost.org/v4.0.0/images/publication-cover.jpg',
facebook: 'ghost',
twitter: '@ghost',
lang: 'en',
locale: 'en',
timezone: 'Etc/UTC',
codeinjection_head: null,
codeinjection_foot: null,
navigation: Array(5) [
{ label: 'Home', url: '/' }, { label: 'JavaScript', url: '/tags/javascript/' }, {
label: 'Nextjs', url: '/tags/nextjs/' },
{ label: 'Reactjs', url: '/tags/reactjs/' }, { label: 'Ghost CMS', url:
'/tags/ghost-cms/' }
],
secondary_navigation: Array(1) [ { label: 'Login', url: '#/portal/' } ],
meta_title: 'My demo post',
meta_description:
'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem
Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen
book.',
og_image: null,
og_title: null,
og_description:
'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem
Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen
book.',
twitter_image: null,
twitter_title: null,
twitter_description:
'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem
Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen
book.',
members_support_address: 'noreply',
members_enabled: true,
members_invite_only: false,
paid_members_enabled: false,
firstpromoter_account: null,
portal_button_style: 'icon-and-text',
portal_button_signup_text: 'Subscribe',
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 19/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
portal_button_icon: null,
portal_plans: Array(1) [ 'free' ],
portal_name: true,
portal_button: true,
comments_enabled: 'all',
url: 'http://localhost:2368/',
version: '5.39'
}
The getNavigation function returns the settings data, and then we pass the data as props
into the header and footer components.
Our Main layout.tsx file works server side. It helps fetch data on the server side with the
React use hook.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 20/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// Layout.tsx
import "./globals.css";
import BlogLayout from './BlogLayout'
import { getNavigation, } from "./ghost-client"
import { use } from "react"
import type { Settings } from "@tryghost/content-api"
return (
<body
style={{
'--bg-color': settings?.accent_color ? settings.accent_color : "",
}}
className={` bg-[--bg-color] dark:bg-gray-900`}>
<BlogLayout setting={settings}>
{children}
</BlogLayout>
</body>
</html>
)
}
BlogLayout component
The BlogLayout component works on the client side. In the Next.js app folder, you can
easily convert your server-side component to the client side with the following "use client"
syntax.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 21/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
The purpose of the BlogLayout component is to contain the ThemeProvider, header, and
footer. ThemeProvider is a high-order component, and it provides additional functionality, like
changing the theme from dark to light. We wrap the intra-site with ThemeProvider's higher
component. In the old pages directory, we achieve similarly functionally with nextjs _app.ts
custom app.
ThemeProvider component helps to change the theme from light to dark mode.
"use client"
// BlogLayout.tsx
}
export default Layout
Next.js has a special app/page.tsx file for designing and building the home page. Our blog
website's home page looks like what you see below. We import the header, card, pagination,
and footer on the home page. The header and footer are part of layout.tsx.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 22/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Home page
First, we fetch all posts data from Ghost CMS with the help of the getPosts function, which I
defined in the ghost-client.ts file.
// ghost-client.ts
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 23/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
By default, the api.post.browse() returns only post data, but you can easily extend it. In
every article or post data, we also include tags and authors with the help of include. Then
we set the article limit to ten.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 24/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
[
{
id: '6422a742136f5d40f37294f5',
uuid: '8c2fcfda-a6e4-4383-893b-ba18511c0f67',
title: 'Demo Posts with Nextjs and Ghost Editor',
slug: 'demo-posts-with-nextjs-and-reactjs',
html: `<p><strong>Lorem Ipsum</strong> is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry's standard dummy text si
nce the 1500s when an unknown printer scrambled a galley of type and scrambled it to
make a type specimen book. </p><p>It has survived five centuries and the leap i
nto electronic typesetting, remaining essentially unchanged. </p><p>It was
popularised in the 1960s with Letraset sheets containing Lorem Ipsum passages and,
more r
ecently, desktop publishing software like Aldus PageMaker, including versions of
Lorem Ipsum.</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascap
tion"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-
gallery-image"><img src="http://localhost:2368/content/images/2023/03/Build-and-d
eploy.png" width="1500" height="400" loading="lazy" alt
srcset="http://localhost:2368/content/images/size/w600/2023/03/Build-and-deploy.png
600w, http://localhost:2
368/content/images/size/w1000/2023/03/Build-and-deploy.png 1000w,
http://localhost:2368/content/images/2023/03/Build-and-deploy.png 1500w" sizes="(min-
width: 720px)
720px"></div><div class="kg-gallery-image"><img
src="http://localhost:2368/content/images/2023/03/Build-and-deploy-profile-1.png"
width="1500" height="400" loading
="lazy" alt srcset="http://localhost:2368/content/images/size/w600/2023/03/Build-and-
deploy-profile-1.png 600w, http://localhost:2368/content/images/size/w1000/2023
/03/Build-and-deploy-profile-1.png 1000w,
http://localhost:2368/content/images/2023/03/Build-and-deploy-profile-1.png 1500w"
sizes="(min-width: 720px) 720px"></div>
</div><div class="kg-gallery-row"><div class="kg-gallery-image"><img
src="http://localhost:2368/content/images/2023/03/Build-and-deploy-profile--1--1.png"
width="15
00" height="400" loading="lazy" alt
srcset="http://localhost:2368/content/images/size/w600/2023/03/Build-and-deploy-
profile--1--1.png 600w, http://localhost:2368/co
ntent/images/size/w1000/2023/03/Build-and-deploy-profile--1--1.png 1000w,
http://localhost:2368/content/images/2023/03/Build-and-deploy-profile--1--1.png
1500w" siz
es="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img
src="http://localhost:2368/content/images/2023/03/Build--Test-and-Deploy-profile-
1.png" width
="1500" height="400" loading="lazy" alt
srcset="http://localhost:2368/content/images/size/w600/2023/03/Build--Test-and-
Deploy-profile-1.png 600w, http://localhost:2
368/content/images/size/w1000/2023/03/Build--Test-and-Deploy-profile-1.png 1000w,
http://localhost:2368/content/images/2023/03/Build--Test-and-Deploy-profile-1.png
1500w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Build and
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 25/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 26/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
src="https://miro.medium.com/v2/resize:fit:1200/1*yAoHfq4Wm2Bp8DU1Dav29Q.png" alt>
</div></a><figcaption>Bookmark<
/figcaption></figure><div class="kg-card kg-header-card kg-width-full kg-size-small
kg-style-dark" style data-kg-background-image><h2 class="kg-header-card-header"
id="thank-you">Thank you</h2></div>',
comment_id: '6422a742136f5d40f37294f5',
feature_image: 'https://images.unsplash.com/photo-1543966888-7c1dc482a810?
crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE2fHxqYXZhc2Ny
a
XB0fGVufDB8fHx8MTY3OTk5MjY1NA&ixlib=rb-4.0.3&q=80&w=2000',
featured: false,
visibility: 'public',
created_at: '2023-03-28T08:37:22.000+00:00',
updated_at: '2023-03-28T08:51:38.000+00:00',
published_at: '2023-03-28T08:50:44.000+00:00',
custom_excerpt: 'It has survived five centuries and the leap into electronic
typesetting, remaining essentially unchanged. ',
codeinjection_head: null,
codeinjection_foot: null,
custom_template: null,
canonical_url: null,
tags: [ [Object] ],
authors: [ [Object] ],
primary_author: {
id: '1',
name: 'Rajdeep Singh',
slug: 'rajdeep',
profile_image:
'https://www.gravatar.com/avatar/dafca7497609ae294378279ad1d6136c?s=250&r=x&d=mp',
cover_image: null,
bio: 'Lorem Ipsum is simply dummy text of the printing and typesetting
industry. ',
website: 'https://officialrajdeepsingh.dev',
location: 'India',
facebook: 'officialrajdeepsingh',
twitter: '@Official_R_deep',
meta_title: null,
meta_description: null,
url: 'http://localhost:2368/author/rajdeep/'
},
primary_tag: {
id: '6422aa9a136f5d40f3729552',
name: 'demo',
slug: 'demo',
description: null,
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 27/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
url: 'http://localhost:2368/tag/demo/'
},
url: 'http://localhost:2368/demo-posts-with-nextjs-and-reactjs/',
excerpt: 'It has survived five centuries and the leap into electronic
typesetting, remaining essentially unchanged. ',
reading_time: 3,
access: true,
comments: true,
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
email_subject: null,
frontmatter: null,
feature_image_alt: 'Demo Posts with Nextjs and Ghost Editor',
feature_image_caption: 'Photo by <a href="https://unsplash.com/@pinjasaur?
utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Paul Esch-Laurent</a> /
<a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-
credit">Unsplash</a>'
},
meta:{
pagination: { page: 1, limit: 10, pages: 2, total: 12, next: 2, prev: null }
}
]
Now we call the getPosts function on the server side. It returns all the post data with the
associated tags and authors. Now you can loop through the data with a map() function.
We pass the data into app/page.tsx to the card.tsx components. We pass the article data
as props into the card component.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 28/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/page.tsx
return (
<>
<main className="container my-12 mx-auto grid grid-cols-1 gap-2 md:gap-3
lg:gap-4 lg:grid-cols-3 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-4">
{
getPost?.map(
item => {
return <Card key={item.uuid} item={item} />
})
}
</main>
</>
)
}
Card component
I designed a basic card for the blog. The card component looks like this:
Card component
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 29/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
I rendered every item of data coming from the home page as props and showed it on the site
with Card.tsx .
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 30/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// Card.tsx
return (
<div className="max-w-full bg-white dark:bg-gray-800" >
{
item.featured !== null && item.feature_image !== undefined ? <Link href=
{`/read/${item.slug}`}>
<Image className="rounded-lg p-3" width={1000} height={324} src=
{item.feature_image} alt={item.feature_image_alt || item.title} />
</Link> : " "
}
<div className="p-3">
<Link href={`/read/${item.slug}`}>
<h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900
dark:text-white">
{item.title}
</h5>
</Link>
</div>
</div>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 31/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 32/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 33/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Reading page
First, we get a single article from the Ghost CMS API based on its slug. We pass it to the
Card component with the Link component.
// ghost-client.ts
The getSinglePost(<you-slug>) function returns data about a single article, and you can
render that data on the page.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 34/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/read/[slug]/page.tsx
return (
<>
<main className="pt-8 pb-16 lg:pt-16 lg:pb-24 dark:bg-gray-900">
{
getPost.primary_tag ? <Link href=
{`/tags/${getPost?.primary_tag.slug}`}>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 35/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
# {getPost?.primary_tag.name}
</Link> : ""
}
</div>
<p className="lead">
{getPost.excerpt}
</p>
{
getPost.published_at ? <time className="text-base font-light
text-gray-800 dark:text-white mx-1" dateTime={getPost?.published_at} title=
{format(new Date(getPost?.published_at), 'yyyy-MM-dd')}>
{format(new Date(getPost?.published_at), 'dd MMMM, yyyy')}
</time> : ""
}
</div>
</address>
</header>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 36/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
<figure>
<Image className="mx-auto" width={1000} height={250} src=
{getPost.feature_image} alt={getPost.feature_image_alt} />
<figcaption className="text-center"
dangerouslySetInnerHTML={{
__html: getPost?.feature_image_caption
}}></figcaption>
</figure>
</article>
</div>
</main>
<Newsletter />
</>
)
}
export default Read
You render the post's HTML data with dangerouslySetInnerHTML . But you need to write
lots of CSS to handle the dynamic content coming from the Ghost CMS API.
Generate the static site with the generateStaticParams function. Before, we used to
getStaticProps function.
// ghost-client.ts
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 37/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
I designed a simple tag page for the blog. The tag page shows articles related to the tags
that are used.
You can also create a category page. Tag pages and category pages use the same logic and
functionalities.
Tag page
Similar to the reading page, we'll get articles based on tags from the Ghost CMS API.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 38/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// ghost-client.ts
The getTagPosts(<tag-slug>) function returns all the available posts related to a specific
tag.
After receiving all posts with getTagPosts(), we render all posts with the help of the map()
method.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 39/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/tag/[slug]/page.tsx
allTags?.map(item => {
allTagsItem.push({
slug: item.slug,
})
})
return allTagsItem
if (tagPosts.length === 0) {
notFound()
}
return (
<aside aria-label="Related articles" className="py-8 lg:py-24 dark:bg-gray-800">
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 40/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
{
tagPosts.map(
item => <Card key={item.uuid} item={item} />
)
}
</div>
</div>
</aside>
)
Generate the static site with the generateStaticParams function. It helps to generate slugs
of the static build.
// ghost-client.ts
For the demo blog, I designed a basic page for the author.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 41/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Author page
We'll build this in a similar way as we built the tag page. First, we get the author's metadata
and author posts from the Ghost CMS API.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 42/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// ghost-client.ts
We render the posts data with the help of the map() method.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 43/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/author/[slug]/page.tsx
allAuthor.map(item => {
allAuthorItem.push({
slug: item.slug,
})
})
return allAuthorItem
return (
<>
<section className="dark:bg-gray-900">
<div className="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 44/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
{
getAuthor?.profile_image !== undefined ? <Image height={30} width={30}
className="w-36 h-36 p-2 rounded-full mx-auto ring-2 ring-gray-300 dark:ring-gray-
500" src={getAuthor?.profile_image} alt={getAuthor?.name} /> : ""
}
{
getAuthor?.name ? <h2 className="mb-4 mt-4 text-4xl tracking-tight
font-bold text-center text-gray-900 dark:text-white">
{getAuthor?.name.split(" ")[0]}
<span className="font-extrabold">
{getAuthor?.name?.split(" ")[1]}
</span>
</h2> : ""
}
{
(getAuthor?.website !== null) ? (<li>
<Link href={getAuthor?.website} className="block py-2 pl-3 pr-4
text-gray-700 hover:text-blue-700 dark:hover:text-blue-700 rounded md:p-0 dark:text-
white" aria-current="page">
<FaGlobe />
</Link> </li>) : " "
{
(getAuthor?.twitter !== null) ? (<li>
<Link href={getAuthor?.twitter} className="block py-2 pl-3 pr-4
text-gray-700 rounded hover:text-blue-700 dark:hover:text-blue-700 md:p-0 dark:text-
white" aria-current="page">
<FaTwitter />
</Link>
</li>) : " "
}
{
(getAuthor?.facebook !== null && getAuthor.facebook !== undefined) ?
(<li>
<Link href={getAuthor?.facebook}
className="block py-2 pl-3 pr-4 text-gray-700 rounded
hover:text-blue-700 dark:hover:text-blue-700 md:p-0 dark:text-white"> <FaFacebook />
</Link>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 45/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
</ul>
</div>
</div>
</section>
{
allAuthor?.map(item => <Card key={item?.uuid} item={item} />)
}
</div>
</div>
</aside>
</>
)
}
export default AuthorPage
To generate the author slug for the static site, we need to use the generateStaticParams
function. We do not need anything else to build the static site.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 46/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// ghost-client.ts
allAuthor.map(item => {
allAuthorItem.push({
slug: item.slug,
})
})
return allAuthorItem
Firstly, you need to fetch all pages and the single pages data from the Ghost Content API.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 47/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// ghost-client.tsx
The getSinglePage(page-slug) function returns the single page data based on the page
slug, and the getAllPages() function returns all the available published page data to
generate the dynamic params with the generateStaticParams() function.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 48/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/pages/[slug]/page.tsx
return (
<>
<main className="pt-8 pb-16 lg:pt-16 lg:pb-24 dark:bg-gray-900">
<div className="flex justify-between px-4 mx-auto max-w-screen-xl ">
</article>
</div>
</main>
</>
)
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 49/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
}
export default Pages
meta:{
pagination: { page: 1, limit: 10, pages: 2, total: 12, next: 2, prev: null }
}
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 50/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// Pagination.tsx
let paginationItems = []
return (
<li>
{
item.prev ? <Link href={item.prev === 1 ? "/" :
`/pagination/${item.prev}`} className="px-3 py-2 mr-2 border border-transparent
rounded-md leading-tight bg-white hover:text-blue-700 dark:bg-gray-800 dark:text-
gray-400
dark:hover:bg-gray-700 dark:hover:text-white">
Prev
</Link> : " "
}
</li>
{paginationItems}
<li>
{
item.next ? <Link href={`/pagination/${item.next}`} className="px-3 py-2
ml-2 border border-transparent rounded-md leading-tight bg-white hover:text-blue-700
dark:bg-gray-800 dark:text-gray-400
dark:hover:bg-gray-700 dark:hover:text-white">
Next
</Link> : " "
}
</li>
</ul>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 51/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
</nav>
When you call the api.posts.browse({ limit: 10 }) request, the API endpoint returns
ten posts and a meta object with pagination.
[
{title: 'Demo Posts with Nextjs and Ghost Editor',... },
{title: Trigger the hook and rebuild the nextjs site',... }
meta:{
pagination: { page: 1, limit: 10, pages: 2, total: 12, next: 2, prev: null }
}
]
Now based on meta, we can create pagination and pass meta.pagination as props to the
Pagination component.
// src/app/page.tsx
return (
<>
{/* rest of code */}
<Pagination item={getPost.meta.pagination} />
</>
)
}
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 52/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// ghost-client.tsx
//
export async function getPaginationPosts(page: number) {
return await api.posts
.browse({
include: ["tags", "authors"],
limit: 10,
page: page
})
.catch(err => {
throw new Error(err)
});
}
The getPosts is used to render the Pagination component on the pagination page. The
important part is the getPaginationPosts(<pagination-page-number>) function, which
returns posts based on the pagination page number.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 53/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/pagination/[item]/page.tsx
return paginationItem
return (
<>
{
getPost?.map(
item => {
return <Card key={item.uuid} item={item} />
})
}
</main>
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 54/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
</>
)
}
Next.js SEO
If you are a blogger, you know how important SEO is in helping people find your blog and
your articles. For SEO, Next.js provides a generateMetadata function to generate dynamic
SEO metadata for your site. This means that you don't need any additional packages for
SEO.
For the purpose of this example, I'll explain how to enable SEO for the blog only on the
Homepage and the Reading page. You can use the same logic to enable it on any of your
other pages.
// ghost-client.ts
// src/app/page.tsx
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 55/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// ghost-client.ts
The generateMetadata have params props, which help access the slug. Then, based on the
slug, we get the data and return it.
return {
title: metaData.title,
description: metaData.description,
keywords: tags,
openGraph: {
title: metaData.title,
description: metaData.excpet,
url: metaData.url,
keywords: tags,
images: [
{
url: metaData.feature_image,
},
],
locale: metaData.locale,
type: 'website',
},
}
}
Enabling search on a static blog is hard to do from scratch. Instead, you can use a third-
party Node page like Orama or Flex search.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 56/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
For our demo, we created a very simple search bar functionality without installing any
additional packages.
// ghost-client.ts
After we convert it into a string with the help of JSON.stringify(), we then create a new
search.json file. On every request, it updates or rewrites our search.json file.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 57/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
// src/app/page.tsx
// Enable getSearch
try {
} catch (error) {
console.log('error : ', error)
}
return (
<>
<main className="container my-12 mx-auto grid grid-cols-1 gap-2 md:gap-3
lg:gap-4 lg:grid-cols-3 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-4">
{/* rest code... */}
</main>
</>
)
}
When you enter the text in the search input, based on the text query, we compare the query
or text in the serach.json file data. If it matches the article title with the query, then we store
the searchPost variable, and finally we render the stored data in the searchPost variable
page.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 58/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
"use client"
function Search() {
useEffect(() => {
searchPost.length = 0;
if (item?.title.trim().toLowerCase().includes(query?.trim().toLowerCase())) {
searchPost.push(item)
}
})
}, [query])
return (
<Popover.Root>
<Popover.Trigger asChild>
<button
className="cursor-pointer outline-none"
aria-label="Search"
>
<FaSearch />
</button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content
className="rounded p-2 bg-white dark:bg-gray-800 w-[480px] will-change-
[transform,opacity] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-
[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-
[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-
slideRightAndFade"
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 59/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
sideOffset={5}
>
<div className='my-2'>
<label htmlFor="default-search" className="mb-2 mt-5 text-sm font-medium
text-gray-900 sr-only dark:text-white">Search bar </label>
<div className="relative">
<div className="absolute inset-y-0 left-0 flex items-center pl-3
pointer-events-none">
<svg className="w-5 h-5 text-gray-500 dark:text-gray-400" fill="none"
stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path
strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0
11-14 0 7 7 0 0114 0z"></path></svg>
</div>
<input type="search" id="default-search" onChange={(event) =>
setQuery(event?.target.value)} className="block w-full p-4 pl-10 text-sm text-gray-
900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-
blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-
white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Start
searching here ..." required />
</div>
</div>
return (
<div key={item.uuid} className='my-3'>
<div className="text-white my-2 py-2 bg-blue-400 dark:bg-gray-900
dark:hover:bg-blue-400 border-none rounded-md dark:text-white">
<Link href={`read/${item.slug}`} className="relative inline-flex
items-center rounded-lg w-full px-4 py-2 text-sm font-medium">
{item.title}
</Link>
</div>
</div>
)
}) : " "
</Popover.Content>
</Popover.Portal>
</Popover.Root >
)
}
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 60/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Error Handling
Next.js has two types of error handling. the first is layout-based, and the second is global
error handling. For the demo here, we'll use layout-based error handling.
Next provides a special type of error.tsx file to handle errors on your site. It does not
handle 404, 500, and so on – it handles only runtime errors.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 61/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
useEffect(() => {
console.error(error);
}, [error]);
return (
<section className="dark:bg-gray-900 my-16">
</div>
</div>
</div>
</section>
);
}
To handle 404 errors in the Next.js app folder, you need to create a not-found.tsx file in
your root level.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 62/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
404 error
function NotFound() {
return (
<section className="bg-white dark:bg-gray-900 my-16">
<div className="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
<div className="mx-auto max-w-screen-sm text-center">
<h1 className="mb-4 text-7xl tracking-tight lg:text-9xl text-primary-600
dark:text-primary-500">404</h1>
<p className="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-
4xl dark:text-white"> Something wrong</p>
<p className="mb-4 text-lg font-light text-gray-500 dark:text-gray-400">
Sorry, we cant find that article. You will find lots to explore on the
home page.
</p>
<Link href="/" className="inline-flex text-white bg-black dark:bg-white
dark:text-black p-3 hover:bg-gray-800 my-4">Back to Homepage</Link>
</div>
</div>
</section >
)
The big issue with the not-found.tsx error file is that it doesn't show automatically in Next
(v13.3.0). To show a 404 error, you need to show the error manually. Here's how you do that:
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 63/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
if (!getPost) {
notFound()
}
return (
<main className="pt-8 pb-16 lg:pt-16 lg:pb-24 dark:bg-gray-900">
</main>
)
}
The best solution is to use webhooks. Ghost provides webhook support. If you update an
existing post or write a new one, it'll update in Ghost.
In the demo project, we're using Vercel webhooks to deploy our blog. When we create a new
blog or update something on the site, Ghost triggers the Vercel webhook. Then Vercel
rebuilds the site as needed.
You do not need to write the code for this – just follow along and copy-paste as you go.
Vercel dashboard
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 64/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
Then click on the Git tab. After scrolling down, you can see the deploy hook selection.
Enter your webhook name and branch name and click on the "create hook" button.
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 65/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
When something changes in Ghost, it triggers the Vercel webhook URL. Then Vercel
redeploys the blog site.
To integrate the Vercel webhook with Ghost, just follow these steps:
Ghost dashboard
Ghost settings
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 66/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 67/68
12/1/24, 12:28 PM How to Build a Blog with the Ghost API and Next.js
First, enter the name, then select Event and paste the URL which you copied from the Vercel
dashboard.
Based on the event, Ghost will call the webhook, and your website will rebuild. Redeploys
take time based on how big your site is, and so on.
Conclusion
Everything should work well using Next.js and the Ghost CMS as we've worked through in
this tutorial.
But some of the Ghost editor components, like toggles, where you need JavaScript
interaction, don't work. You can solve this by writing your own JavaScript or getting a
JavaScript file for Ghost and adding it to the read/[slug]/page.tsx file.
You can save a lot of money on hosting by combining Next.js and the Ghost CMS API, but
you lose some features like inbuilt signup, login, accounts, subscriptions, search bar, and
member access levels.
You can share and follow me on Twitter and Linkedin. If you like my work, you can read more
content on my blog, the officialrajdeepsingh.dev, frontend web, and Sign up for my free
newsletter.
You can also check out awesome-next, a curated list of awesome Nextjs-based libraries that
help build small and large-scale applications with Next.js.
Here are some additional resources you can use if you need more help or information while
going through this tutorial:
https://ghost.org/docs/jamstack/next/
https://www.digitalocean.com/community/tutorials/how-to-build-your-blog-on-digitalocean-
with-ghost-and-next-js
https://ghost.org/docs/content-api/
https://beta.nextjs.org/docs/getting-started
I write tons of articles on Next. If you are interested in Next and related stuff, you can follow
me on Medium and join the frontend web publication.
Rajdeep Singh
https://www.freecodecamp.org/news/build-a-blog-website-with-ghost-api-and-nextjs/ 68/68