In this step-by-step guide, you will learn how to harness the power of Gatsby, a blazing-fast static site generator, and Strapi, a composable CMS, to create a dynamic yet performant blog.
Whether you are a developer looking to expand your skillset or a content creator seeking a flexible and efficient way to manage your blog, this tutorial will equip you with the knowledge to create a sleek and responsive static blog website. Let's dive in!
Why Choose Gatsby and Strapi?
Gatsby: Blazing-Fast Static Site Generator
Gatsby is a sophisticated static site generator that utilizes React and GraphQL to build lightning-fast websites. It pre-renders pages at build time, ensuring optimal performance and a superior user experience. Its extensive plugin architecture makes it easy to enhance your site's functionality while maintaining exceptional speed and SEO benefits.
Gatsby offers three methods for rendering content:
- Static Site Generation (SSG)
- Deferred Static Generation (DSG)
- Server-Side Rendering (SSR)
In this tutorial, we'll focus on Static Site Generation (SSG), where the entire site is pre-rendered into HTML, CSS, and JavaScript at build time. These static assets are then served directly to the browser, resulting in faster load times and improved performance.
Gatsby leverages GraphQL, a query language for APIs, to enable pages and components to declare the data they need. This data is then provided by the server at build time, allowing for efficient data management and optimized builds.
Strapi: The Leading Open-Source Headless CMS
Strapi is an open-source headless Content Management System (CMS) that revolutionizes content management. Based on Node.js, it allows you to build customizable APIs quickly. Unlike traditional CMS platforms, Strapi separates the backend from the frontend, providing a flexible and customizable API that allows you to manage content efficiently.
Strapi offers several benefits:
- Flexibility and Customization: Define custom content types and relationships without complex configurations.
- Open-Source Community: Backed by a large community of contributors and users willing to help.
- Self-Hosted or Cloud Options: You can self-host Strapi or leverage Strapi Cloud, a fully managed platform to boost your content velocity.
The Power of Combining Gatsby and Strapi
Integrating Gatsby with Strapi creates a powerful synergy that addresses both performance and content management needs. This combination is particularly effective for content-heavy applications like blogs, e-commerce sites, and marketing websites.
By leveraging these tools together, you get the best of both worlds:
- Gatsby's Performance Optimization: Benefit from static site generation, resulting in lightning-fast load times and improved SEO.
- Strapi's Flexible Content Management: Manage content efficiently with an intuitive interface, allowing content editors and developers to work seamlessly.
Related Articles:
Prerequisites
To follow this tutorial some basic knowledge of HTML, CSS, and JavaScript is required.
Additionally, you will need the following tools installed on your computer:
- Node.js Node
v16.x
,v18.x
, andv20.x
Only LTS versions of Node are supported - Node.js Package manager: npm or yarn
- Python (for SQLite Database)
- Git for version control
If you prefer to see the ready-made version here are the links to the blog GitHub repo, and blog live link.
Set up Project Folder
On your terminal, create a folder named gatsby-strapi-blog
to store your project files.
mkdir strapi-gatsby-blog
Navigate into the newly created folder.
cd strapi-gatsby-blog
Initialize your project for version control.
git init
Strapi Backend Set Up
Create a Standard Strapi App
Create your Strapi app in a folder named backend
.
yarn create strapi-app backend --quickstart --no-run
- The
quickstart
flag sets up your Strapi app with an SQLite database. - The
no-run
flag prevents your Strapi app from automatically starting up.
After the installation process completes, a new folder named backend
will be created in the root of your project folder.
Commit the first changes for your project.
git commit -a -m "Initial commit"
Create an Admin user for your Strapi app
Navigate into the Strapi app backend
folder.
cd backend
Create a new admin user for your Strapi app using the following command:
yarn strapi admin:create-user --firstname=Kai --lastname=Doe --email=chef@strapi.io --password=Gourmet1234
Take note of the email and password that you will use later to log in to your Strapi Admin Dashboard.
git commit -a -m "Added Strapi Admin User"
Log in to your Strapi App
Start your strapi app by executing the following command in your backend
folder:
1yarn develop
The Strapi backend server will start running on port 1337
. Visit http://localhost:1337/admin
in your browser and you should see a login form for the Strapi Admin Panel.
Enter the credentials that you saved earlier to access the Strapi Admin Dashboard.
Build your Content
You will use Strapi to create a data structure for your blog posts, then add some entries and publish them, so that the API for your content can be consumed.
Our blog app will contain posts. The posts will have the following data types:
title
: The post's titledescription
: The post's descriptioncontent
: The post's contentslug
: The unique slug for the post's URLcover
: An image to act as the cover for the postauthor
: The post's authorcategory
: The category for each post.
You can find the raw content text for the blog app by following this link.
Create Collection Types
In this step, you will create 3 collection types to store the content for our blog posts. These are:
- Post
- Category
- Author
In your Strapi Admin Panel, select the Content-Type Builder
option and click on + Create new collection type
. Name the collection Post
and click Continue
In the Select a field for your collection type
menu select Text
.
In the new pop-up modal, name your Text field title
and select Short text
for the type.
Click on + Add another field
.
Select Text
field once again. Name it description
and select Long text
for its type.
Click on + Add another field
.
Select Text
field. Name it cover
and select Short text
for its type.
Then click on + Add another field
.
Select Rich text
field.
Name it content
and click on + Add another field
.
Select Date
field.
In the Add new Date field
modal, name it date
, and choose date (ex: 01/01/2023)
for the type.
Select UID
field.
In the Add new UID field
, name your UID, slug
, and select title
for the attached field. Click on Finish
.
Review the fields for your Post collection and click on Save
.
Wait for your Strapi server to restart.
Create a new collection type and name it Author
.
Add the following fields to the Author collection type:
- Text
- Text
- Relation
For the Text
field, name it name
with the type of Short text
.
For the second Text
field, name it avatar
with the type of Short text
.
For the Relation
field select a one-to-many relationship between Authors
and Posts
.
Click on Save
and wait for your server to restart. Your Author
collection type should be similar to the screenshot below.
Create a new collection type and name it Category
. This is the last collection type for your blog.
Add the following fields to the Category
collection:
- Text
- UID
- Relation
Name the Text
field name
with a Short text
type.
Name the UID
field slug
and select name
for the attached field.
For the Relation
field select a one-to-many relationship between Category
and Posts
.
Click on Save
and wait for your server to restart. Your Category
collection type should be similar to the screenshot below.
The final data architecture for your Post collection type should look like the screenshot below:
Open up a new terminal session and in your project folder strapi-gatsby-blog
, commit the changes you have made into version control with the following command:
git commit -a -m "Added Collection Types"
Add Posts
Now that you have configured a content structure for your blog backend. The next step is to add content by creating new entries for your collections.
Data to populate your content types can be found on this link: Strapi Gatsby Blog Posts Data.
Select the Content Manager
option in the Admin Panel. Click on the Author
collection type and select + Create new entry
.
Give your author a name
and add an image link for the author's avatar. Click on Save
then Publish
.
Repeat the same procedure for the second author and your Author entries should be similar to the screenshot below.
Next, add entries for the category
collection. Your categories collection should be similar to the screenshot below.
Add entries for the Post
collection. Remember to add the author
and category
relation fields for each post.
After publishing your posts, your Post
collection should be populated with entries as seen in the screenshot below.
Allow Access to your API
For security reasons, the API access is restricted by default. You will need to make the content available publicly through the API.
- Click on
Settings
underGENERAL
at the bottom of the main navigation. Under Users & Permissions Plugin
, chooseRoles
.- Click on
Public role
. - In the Permissions tab, find
Author
, click on it, and select the checkboxes next tofind
andfindone
. - Repeat the same procedure for the
category
andAuthor
collection.
Next, allow access to the Content-Types Builder
plugin by checking Select all
for both CONTENT-TYPES
and COMPONENTS
.
Now your API is publicly available but in Read-only mode. This is sufficient for your static blog.
Open up a new terminal session and test whether your API is working by entering the following command:
curl http://localhost:1337/api/posts
If all is working you should get a JSON payload with a list of all your posts
Set up GraphQL plugin
Strapi supports exposing your content via a GraphQL API. To enable the feature you will install the GraphQL plugin.
Stop the Strapi development server in your terminal. In the backend
folder where your Strapi app is installed, run the following command:
yarn strapi install graphql
Commit the changes to version control.
git commit -a -m "Added GraphQL to Strapi server"
After a successful installation, restart your Strapi server by running the following command:
yarn develop
Visit http://localhost:1337/graphql
to access the Strapi GraphQL playground. Test out your Strapi GraphQL server with the following query to fetch all the posts.
1 query{
2 posts{
3 data{
4 attributes{
5 title
6 description
7 content
8 date
9 slug
10 cover
11 author{
12 data{
13 attributes{
14 name
15 avatar
16 }
17 }
18 }
19 category{
20 data{
21 attributes{
22 name
23 slug
24 }
25 }
26 }
27 }
28 }
29 }
30 }
Click on the Play
icon and wait for the response. If all is working the response you will get should be similar to the image below.
For more information on the features that the Strapi GraphQL Playground check out this article about a deep dive into Strapi GraphQL.
Gatsby Frontend Set Up
Create A New Gatsby Site
In a new terminal session, navigate to the root of your project folder strapi-gatsby-blog
and run the following command:
npm init gatsby
This will start up an interactive prompt to help you create a new Gatsby site. Respond to the prompts as follows:
- What would you like to call your site?
Strapi Gatsby Blog Site
- What would you like to name the folder where your site will be created?
frontend
- Will you be using JavaScript or TypeScript?
JavaScript
- Will you be using a CMS?
No (or I'll add it later)
- Would you like to install a styling system?
No (or I'll add it later)
- Would you like to install additional features with other plugins?
Done
Answer Yes
to the final prompt and wait for your Gatsby site to be built. After the build is finished you should see a message similar to the one in the following screenshot:
Install gatsby-source-strapi plugin
One of Gatsby's coolest features is its support for plugins. Gatsby plugins are Node.js packages that you can add to your Gatsby site. They allow you to quickly add new features to your Gatsby site.
Gatsby has a gatsby-source-strapi
used as a source plugin to pull data into Gatsby sites from a Strapi GraphQL API. You will use this plugin for your blog site.
Navigate into the frontend
folder where you have just created your Gatsby site and run the following command:
npm install --save gatsby-source-strapi gatsby-transformer-remark
This installs the gatsby-source-strapi
plugin including the gatsby-transformer-remark
plugin which processes markdown files into HTML.
Edit gatsby-config.js
For your website to pull data from Strapi's GraphQL API, the gatsby-config.js
file in the root of your frontend
folder should be updated. Delete the contents of gatsby-config.js
and update it with the following code:
1//gatsby-config.js
2require("dotenv").config({
3 path: `.env.${process.env.NODE_ENV}`,
4});
5
6const strapiConfig = {
7 apiURL: process.env.STRAPI_API_URL || "http://127.0.0.1:1337",
8 collectionTypes: ["post", "category", "author"],
9};
10
11
12module.exports = {
13 plugins: [
14 {
15 resolve: `gatsby-source-strapi`,
16 options: strapiConfig,
17 },
18 "gatsby-transformer-remark",
19 ],
20};
Update .env.development
with the URL to your Strapi backend:
1STRAPI_API_URL=http://127.0.0.1:1337
Test Strapi Data Node
Before proceeding to write code for the website you need to test if data from Strapi is being loaded into Gatsby's GraphQL Data Layer. You can use Gatsby's GraphiQL Playground for this.
In the directory where your Gatsby site has been installed, run the following command to start up the Gatsby development server:
npm run develop
This should start your Gatsby development server on port 8000
. Visit http://localhost:8000/___graphql
in your browser to open up the Gatsby GraphiQL Playground.
- Open the GraphiQL Explorer pane by clicking on the button labeled “Show GraphiQL Explorer” (looks like a folder with a plus icon).
- Check the
allStrapiPost
field to request data about multiple posts at once. - Check the fields within the
nodes
field liketitle
,date
, etc to build your query. Note how checking the box for a field adds it to the query in the Query Editor. - Click the button in the middle of the page (that looks like a “play” button) to execute the query. Look at the data returned in the Result window.
If data from your Strapi Backend API is being returned in the Result window, then that means your configuration is working. For example, a query like:
1query MyQuery {
2 allStrapiPost {
3 nodes {
4 title
5 description
6 }
7 }
8}
Should return a result similar to this:
1{
2 "data": {
3 "allStrapiPost": {
4 "nodes": [
5 {
6 "title": "What are Role-Based Permissions in a Web Application?",
7 "description": "What are Role-Based Permissions in a Web Application?"
8 },
9 {
10 "title": "What is Prompt Engineering? Top 5 Best Prompts to Get You Started",
11 "description": "What is Prompt Engineering? Top 5 Best Prompts to Get You Started"
12 },
13 {
14 "title": "How to Improve Productivity Using ChatGPT",
15 "description": "How to Improve Productivity Using ChatGPT"
16 },
17 {
18 "title": "How AI Will Change the Landscape of Building Products",
19 "description": "How AI Will Change the Landscape of Building Products"
20 },
21 {
22 "title": "The Benefits of a Headless CMS Like Strapi",
23 "description": "The Benefits of a Headless CMS Like Strapi"
24 },
25 {
26 "title": "Unleashing the Power of Customization with Strapi CMS",
27 "description": "Unleashing the Power of Customization with Strapi CMS"
28 }
29 ]
30 }
31 },
32 "extensions": {}
33}
Create Layout Page
In this step, you will create a Layout
component. This will group all the shared elements to reuse across multiple pages on your blog site. These include the <header>
and <footer>
.
Create a new folder called components
in the src
folder. In the components
folder create 2 new files, named layout.js
and layout.css
. Insert the following code into src/components/layout.js
to define your Layout
component:
1//src/components/layout.js
2//src/components/layout.js
3import * as React from 'react'
4import { Link, graphql, useStaticQuery } from 'gatsby'
5
6
7const Layout = ({ pageTitle, children }) => {
8 const data = useStaticQuery(graphql`
9 query {
10 allStrapiCategory {
11 nodes {
12 name
13 slug
14 id
15 }
16 }
17 }
18 `)
19
20 return (
21 <div class="pagewrapper">
22 <header>
23 <h1>Strapi Gatsby Blog</h1>
24 <ul>
25 <li><Link to="/">Home</Link></li>
26 {
27 data.allStrapiCategory.nodes.map(node => (
28 <li key={node.id}>
29 <Link to={`/${node.slug}`}>{node.name}</Link>
30 </li>
31 )
32 )
33 }
34 </ul>
35 </header>
36 <main>
37 <section class="hero">
38 <h2>Welcome to the hypest blog on the interweb. </h2><p>Checkout something cool!</p>
39 <h2 class="pageTitle">{pageTitle}</h2>
40 </section>
41 <section class="content">
42 {children}
43 </section>
44 </main>
45 <footer>
46 <div>
47 <h2>About</h2>
48 <p>Demo blog site using Strapi and Gatsby, Oct 2023</p>
49 </div>
50 <div>
51 <h2>Article</h2>
52 <p><a href="https://strapi.io/blog">Build a Blog Site using Strapi and Gatsby</a></p>
53 </div>
54 </footer>
55 </div>
56 )
57}
58
59export default Layout
The Layout component will render a header
with the site title and a list of navigation links, a main
element with a dynamic heading (from the pageTitle
prop) with the contents passed into it using the children
prop, and a footer
.
import * as React from 'react'
: This enables you to use JSX inside your.js
file.import { Link, graphql, useStaticQuery } from 'gatsby'
: The GatsbyLink
component is for linking pages within your site and thegraphql
tag helps build the GraphQL query usinguseStaticQuery
.import "./layout.css"
: This imports the styles you will define insrc/components/layout.css
to theLayout
component.
Create Blog Home Page
Next, you will create the home page for the blog site. You will query data from Gatsby's GraphQL Data Layer and render a list of all the posts on the home page.
All pages for Gatsby sites are created in the src/pages
folder.
Stop your Gatsby development server by pressing Ctrl
plus C
on your keyboard. Open up src/pages/index.js
in your text editor. Delete the contents and update it with the following code:
1// src/pages/index.js
2import * as React from 'react'
3import { Link, graphql } from 'gatsby'
4import Layout from '../components/layout'
5
6const IndexPage = ({ data }) => {
7
8 return (
9 <Layout pageTitle="Home Page">
10 <ul class="postlist">
11 {
12 data.allStrapiPost.nodes.map(node => (
13 <li key={node.id}>
14 <Link class="postlink" to={`/${node.slug}`}><h3>{node.title}</h3></Link>
15 <div class="image-wrap">
16 <img class="cover" src={`${node.cover}`} alt={`Cover for ${node.title}`} />
17 <img class="avatar" src={`${node.author.avatar}`} alt={`Avatar for${node.author.name}`}/>
18 </div>
19 <p class="date">{node.date}</p>
20 <p class="name">Written by {node.author.name}</p>
21 <p class="postcategory"><Link to={`/${node.category.slug}`}>Category: {node.category.name}</Link></p>
22 <p class="description">{node.description}</p>
23 </li>
24 )
25 )
26 }
27 </ul>
28 </Layout>
29 )
30}
31
32export const query = graphql`
33query {
34allStrapiPost(sort: {date: DESC}) {
35 nodes {
36 author {
37 avatar
38 name
39 }
40 cover
41 date(formatString: "MMMM D, YYYY")
42 description
43 id
44 slug
45 title
46 category {
47 name
48 slug
49 }
50 }
51 }
52}
53`
54
55export const Head = () => <title>Home Page - Strapi Gatsby Blog</title>
56
57export default IndexPage
Here is an explanation of what the code does:
- The
Layout
component you created earlier is imported to render the reusable parts of the UI. - The snippet starting with
const IndexPage = ({ data }) =>
defines a page component. It returns a JSX element which includes the markup to be rendered when your page loads. It receives adata
prop which is used by a.map()
method to iterate over thenodes
array and render the list of blog posts with each blog post displaying atitle
,description
,cover
,date
,category
, andauthor
. - The code block starting with
export const query = graphql
defines a page query. When the site gets built Gatsby runs the GraphQL query and exports the result to theIndexPage
component as a prop calleddata
. - The last two
export
statements ensure the page gets built.
In your frontend
folder, restart your Gatsby development server:
npm run develop
Visit localhost:8000
in your browser to see the home page of your blog site.
You should see a list of the blog posts in descending chronological order. The links to the individual blog posts will not work since we have not implemented the logic yet.
Create Single Post Page
Gatsby provides the File System Route API which helps with creating pages dynamically. You will use it to dynamically create a single page for each blog post based on the post's slug
attribute.
Create a new file named {strapiPost.slug}.js
in the src/pages
directory and add the following code:
1import * as React from 'react'
2import { Link, graphql } from 'gatsby'
3import Layout from '../components/layout'
4
5const BlogPost = ({ data }) => {
6 return (
7 <Layout pageTitle={data.strapiPost.title}>
8 <img class="postcover" src={data.strapiPost.cover} alt={`Cover for ${data.strapiPost.title}`} />
9 <p class="postdate">{data.strapiPost.date}</p>
10 <img class="postavatar" src={data.strapiPost.author.avatar} alt={`Avatar for${data.strapiPost.author.name}`} />
11 <p class="postauthor">Written by {data.strapiPost.author.name}</p>
12 <p class="postcategory"><Link to={`/${data.strapiPost.category.slug}`}>Category: {data.strapiPost.category.name}</Link></p>
13 <div class="postcontent" dangerouslySetInnerHTML={{ __html: data.strapiPost.content.data.childMarkdownRemark.html }} />
14 </Layout>
15 )
16}
17
18export const query = graphql`
19query ($id: String) {
20 strapiPost(id: {eq: $id}) {
21 author {
22 avatar
23 name
24 }
25 category {
26 name
27 slug
28 }
29 content {
30 data {
31 childMarkdownRemark {
32 html
33 }
34 }
35 }
36 cover
37 date(formatString: "MMMM D, YYYY")
38 description
39 slug
40 title
41 }
42 }
43`
44
45export const Head = ({ data }) => <title>{data.strapiPost.title} - Strapi Gatsby Blog Site</title>
46
47export default BlogPost
- The
Layout
component is imported to render the reusable parts of the UI. - The snippet starting with
const BlogPost = ({ data }) =>
defines a page component. It returns a JSX element which includes the markup to be rendered when your page loads. It receives adata
prop which is used to render the blog post'stitle
,description
,date
,content
,author
, andcover
. - The code block starting with
export const query = graphql
defines a page query. The posts are filtered based on the query variable of the post's$id
so that the correct contents are returned when the page is rendered. - In
export const Head
thetitle
attribute of the post is included in thetitle
of the page.
Restart your Gatsby development server and visit the home page of your blog site on localhost:8000
. Click on any one of the links to an individual blog article and you should see the page loads with the correct content.
Create Category Pages
In your src/pages
folder, create a new file named {strapiCategory.slug}.js
. This will dynamically create routes for each individual category for your blog. Each categroy page will display its own posts.
Add the following code to {strapiCategory.slug}.js
:
1import * as React from 'react'
2import { Link, graphql } from 'gatsby'
3import Layout from '../components/layout'
4
5const Category = ({ data }) => {
6 return (
7 <Layout pageTitle={data.strapiCategory.name}>
8 <ul class="postlist">
9 {
10 data.strapiCategory.posts.map(post => (
11 <li key={post.id}>
12 <Link class="postlink" to={`/${post.slug}`}><h3>{post.title}</h3></Link>
13 <div class="image-wrap">
14 <img class="cover" src={post.cover} alt={`Cover for ${post.title}`} />
15 <img class="avatar" src={post.author.avatar} alt={`Avatar for${post.author.name}`}/>
16 </div>
17 <p class="date">{post.date}</p>
18 <p class="name">Written by {post.author.name}</p>
19 <p class="description">{post.description}</p>
20 </li>
21 )
22 )
23 }
24 </ul>
25 </Layout>
26 )
27}
28
29export const query = graphql`
30query ($id: String) {
31 strapiCategory(id: {eq: $id}) {
32 posts {
33 author {
34 avatar
35 name
36 }
37 cover
38 date(formatString: "MMMM D, YYYY")
39 description
40 slug
41 title
42 id
43 }
44 name
45 id
46 slug
47 }
48}
49`
50
51export const Head = ({ data }) => <title>{data.strapiCategory.name} - Strapi Gatsby Blog Site</title>
52
53export default Category
export const query
defines a page query. The posts are filtered based on the query variable of the category's$id
so that the posts matching the specific category are returned when the page is rendered.- The snippet starting with
const Category = ({ data }) =>
defines a page component. It returns a JSX element which includes the markup to be rendered when your page loads. It receives adata
prop which is used by a.map()
method to iterate over the category'sposts
array and render the list of blog posts with each blog post displaying atitle
,description
,cover
,date
,category
, andauthor
.
Restart your Gatsby development server and visit localhost:8000
and click on one of the categories listed in the header
of your blog page like ai
which means you will be visiting localhost:8000/ai
. You should see a list of blog posts for the ai
category only, likewise for the remaining categories.
Add Styling
Add some styling to your blog site by opening src/components/layout.css
and adding the following CSS code:
1/*src/components/layout.css*/
2
3html, body, div,
4h1, h2, h3, h4, h5, h6,
5ul, li, p, img {
6 margin:0;
7 padding:0;
8}
9
10img {
11 border:none;
12}
13
14* {
15 box-sizing:border-box;
16}
17
18ul,
19li,
20a {
21 list-style: none;
22 text-decoration: none;
23 color: inherit;
24}
25
26a:hover {
27 text-decoration: underline;
28}
29
30.pagewrapper {
31 margin: 0 auto;
32 max-width: 960px;
33}
34
35body {
36 font-size: 1.2em;
37 line-height: 1.5;
38 font-family: Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif;
39 background: #f9f9f9;
40}
41
42header {
43 background-color: #FFF;
44 display: flex;
45 height: 4em;
46 justify-content: space-between;
47 align-items: center;
48 padding: 0 0.5em;
49 position: sticky;
50 top: 0;
51 box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.25);
52 z-index: 100;
53}
54
55h1 {
56 font-size: clamp(0.8em, 2.5vw, 2em);
57}
58
59header ul {
60 display: flex;
61 gap: 1em;
62 align-items: center;
63}
64
65header a {
66 text-transform: capitalize;
67 font-size: clamp(0.8em, 2vw, 1.2em);
68}
69
70.hero {
71 height: 12em;
72 text-align: center;
73 padding: 2em 0;
74}
75
76.hero h2 {
77 text-wrap: balance;
78}
79
80.pageTitle {
81 color: hsl(250, 92%, 60%);
82 text-transform: capitalize;
83}
84
85.postlist {
86 display: grid;
87 grid-template-columns: repeat(3, minmax(0, 1fr));
88 gap: 1.5em;
89 row-gap: 3em;
90 justify-content: center;
91 justify-items: center;
92}
93
94@media (max-width: 960px) {
95 .postlist {
96 grid-template-columns: repeat(2, minmax(0, 1fr));
97 }
98}
99
100@media (max-width: 640px) {
101 .postlist {
102 grid-template-columns: repeat(1, minmax(0, 1fr));
103 }
104}
105
106.postlist h3 {
107 font-size: clamp(0.8em, 1.5vw, 1.5em);
108 text-align: center;
109 padding-left: 1em;
110 padding-right: 1em;
111}
112
113.postlist li {
114 overflow: hidden;
115 border-radius: 1em;
116 box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
117 width: 15em;
118 padding: 1em 0;
119}
120
121.postlist .cover {
122 height: 12em;
123 object-fit: cover;
124 width: 100%;
125}
126
127.image-wrap {
128 position: relative;
129}
130
131.postlist .avatar {
132 object-fit: cover;
133 position: absolute;
134 right: 2%;
135 bottom: -10%;
136 border-radius: 9999px;
137 width: 3em;
138 height: 3em;
139}
140
141.postlist p {
142 padding-left: 0.5em;
143}
144
145.date, .name, .postcategory {
146 font-size: 0.8em;
147}
148
149.postcategory {
150 color: hsl(250, 92%, 60%);
151}
152
153.description {
154 padding-top: 1em;
155 font-size: clamp(0.7em, 1.25vw, 1em);
156}
157
158.postcover {
159 width: 100%;
160 object-fit: cover;
161}
162
163footer {
164 margin-top: 3em;
165 padding: 0.5em;
166 background-color: hsl(250, 92%, 10%);
167 color: hsl(250, 92%, 90%);
168 display: flex;
169 align-items: center;
170 justify-content: space-between;
171 flex-wrap: wrap;
172}
173
174.postcover, .postdate, .postauthor, .postcategory, .postcontent p {
175 padding-bottom: 1em;
176}
177
178.postdate, .postauthor {
179 font-size: clamp(0.6em, 1.2vw, 1.2em);
180}
181
182.postavatar {
183 width: 5em;
184 height: 5em;
185 border-radius: 50%;
186 object-fit: cover;
187}
188
189footer h2 {
190 font-size: clamp(0.5em, 1vw, 1em);
191}
192
193footer p {
194 font-size: clamp(0.4em, 0.8vw, 0.8em);
195 font-weight: 400;
196}
Test out the site with the design added. Your blog site home page should be similar to the screenshot below:
Build Project
Now that your Strapi Gatsby blog is up and running, you will need to build the project and get static files of your blog that can be deployed.
Stop your Gatsby frontend development server and enter the following command: (Make sure your Strapi development server is running)
yarn build
After the build completes, there should be a folder named public
in the root of your Gatsby project folder with all the necessary HTML, CSS, JavaScript, and media files required to view your blog site.
Test out your build by previewing the index.html
file in the public
folder, it should give you the exact same blog page design with all the links working.
Deploy Blog
After building your static blog, you will need to deploy it to a static file host. In this tutorial, you will use Cloudflare Pages, but any other static file hosting service like GitHub Pages, Vercel, Netlify, etc can work.
Create a Cloudflare account by visiting the Cloudflare Signup Page
In the root of your frontend
folder add wrangler
(Cloudflare Command line tool) as a devdependency.
yarn add --dev wrangler
Next, run the following command to deploy your static blog to Cloudflare Pages.
yarn wrangler pages deploy public
Give the wrangler tool permission to access your public
directory and deploy the assets.
Give your project a name like strapi-gatsby-blog
and wait for the wrangler tool to upload the assets to your site.
After deployment is complete you should get a unique URL where your site has been deployed.
You can check for my deployment at Tutorial Deployment Link.
Bonus
If you want to deploy your Strapi Backend Server as well, check out this tutorial: How to Deploy your Strapi Project to Strapi Cloud.
Maintenance and Updates
Maintaining your blog involves keeping your dependencies updated and ensuring the continued performance and security of your application.
Regular Updates
- Strapi: Regularly check for updates and apply them to benefit from security patches and new features.
- Gatsby: Keep your Gatsby version and plugins up to date.
Monitoring Performance
Use monitoring tools to keep an eye on your site's performance and uptime.
- Google Analytics: Track user engagement and page views.
- Lighthouse: Audit your site's performance, accessibility, and SEO.
Backup and Recovery
Implement a backup strategy for your Strapi data, especially if you're self-hosting.
- Database Backups: Regularly back up your database.
- Media Assets: Store media files in a cloud storage service with versioning enabled.
Conclusion
By combining Gatsby and Strapi, you've created a powerful and efficient static blog that offers excellent performance and a flexible content management system. This setup not only provides a great developer experience but also ensures your readers enjoy fast load times and a seamless experience.
Feel free to expand upon this foundation by adding features like search functionality, comment systems, or more advanced SEO optimizations.
Further Reading:
Mark Munyaka is a freelance web developer and writer who loves problem-solving and testing out web technologies. You can follow him on Twitter @McMunyaka