[Next.js + Strapi] Build my portfolio website with Next.js, TailwindCSS, and Strapi V4)

The code structure for the full-stack web application — https://www.amyjuanli.com


What is the project (web application) about?

I am obsessed with the idea of having my my personal website in public as it serves as an effective vehicle to help me communicate with people. For some reason (may be I was too lazy), I built (sort of) my personal website using Ghost last year. Although I was very satisfied with the nice dashboard to allow me create the content smoothly and beautifully. But, as a full-stack web developer, I don’t feel right to ‘outsource’ the app development to other platform, so I started to re-design and re-built my website with Next.js as client side and Strapi V4 as the CMS as well as a Restful API provider.

What does the project do?

~ The sections (functionalities) of the website project

  • Blog
  • Works (project) description
  • Personal professional profile
Homepage of my site

Tech Stack and tools

~ Text Editor

  • Terminal + Nvim

Building the full-stack application with Next.js and Strapi V4

Let me walk you through the introduction of Next.js, TailwindCSS and Strapi V4 and how did I implement them in my website project.

Let’s first introduce Strapi V4 to our project since we wants to set up API first and test them in Postman in local environment.

Strapi V4

Accelerating the delivery of modern digital experiences. Strapi enables content-rich experiences to be created, managed and exposed to any digital product, channel or device.

Why I chose Strapi V4? What’s the use?

Here are the demands and of my personal website project:

  • I need to create and update content easily including the blog posts, and my works description pages, as well as managing media files effectively.
  • I don’t need to deal with multiple writers situations since I am the only writer, no team (not now, at least).
  • I need to finish this project in no more than two weeks as I have my startup project to work on.

I either need to build the Content Management System from scratch, or leverage the existing one. Besides, I don’t have sufficient time to write backend code from scratch to create RestAPI which would be consumed by the client app. Strapi satisifies these two requirements. So, I chosen it.

The only problem is I don’t know Strapi until the moment I planned on re-building my personal website. But luckily it’s not hard to pick up. Learn by work.

Install & run Strapi app

$ npx create-strapi-app@latest my-project

Here is our Strapi app project structure:

$ npm run development

Go to http://localhost:1337

Click the Open the administration button

Log in with your own Strapi account

Log in with your Strapi account (create one if you don’t have one yet by just inputting your favourite email and password to create one account), then we see our Strapi content management system:

Content-Type Builder

Step 1: Create new collection type

Click Create new collection type button to create a new collection type (represent the repeatable item)

My Article Collection Type looks like this:

Select the fields for the Article collection type:

And the result looks like this in my case:

Explanation: In my case, I create Collection Types of Article for my blog item, Work for my product item, Category for blog post (since I will have blog in different fields like FrontEnd, BackEnd, Docker, Vim, Travel, etc.), Writer for the author of blog post item and product item. As I probably invite my friends to write some blogs or make some collaborations with other developers on some product, so I treat the Writer as a Collection Type rather than Single Type.

Step 2: Create new single type

I have Single Types such as Homepage (you can give whatever name you prefer), Blog-page, Works-page, and About-page.

Explanation: Collection Types for the repeatable items, while the Single Types for the non-repeatable item. The reason I have these Single Types for different pages on my website is because I want to customise the SEO information for each page in case people share different page link on social media. Later on, I will share how I implement the SEO inside the code of Next.js app.

After building the Collection Types and Single Types, now comes to fill up the content (data) which will be handled by

Step 3: Create new entry

Strapi is a CMS which allows us to create entry easily. Let’s create our first blog post (article). Open the Content Manger:

Click the Create new entry button to create our first blog post:

As you see, the fields — title, excerpt, content, slug, image — come out of the Collection Type of Article.

Since we need image for our blog post, so let’s upload media from Media Library:

We also need to create entry for Writer/Category collection type as blog post need them as well.

Let’s create entry for our first blog post:

Step 4: Save/Publish new entry.

Clicking Save button gives you a draft version. If we want to retrieve (send a HTTP GET request) this post, I have to publish it (just click the Publish button).

Step 5: Test API using Postman

Let’s fetch the newly created blog post via the API generated by Strapi

For any Content Type we have created, Strapi automatically creates API endponts for us. For example, we can fetch the articles through http://localhost:1337/api/articles

To refine the results, such as sorting the results if you have multiple items, or populate some fields data), you could leverage the API parameters.


You can find the detailed information about Rest API in Strapi official documentation page.


TailwindCSS helps you rapidly build modern websites without ever leaving your HTML. It is a utility-first CSS framework packed with classes like flex, pt-4 that can be composed to build any design.

The reason I chose TailwindCSS is also because it does help me focus on my work without writing separate CSS files. In the next, we will discuss how to set up and implement TailwindCSS in Next.js app.


  • Create a Next.js app
$ npx create-next-app my-nextjs-app
  • Install Tailwind CSS with Next.js
$ cd my-nextjs-app
$ npm install -D tailwindcss postcss autoprefixer
$ npx tailwindcss init -p
  • Configure template paths in your tailwind.config.js file
  • Add the Tailwind directives to your CSS
  • Now we can using Tailwind by providing className

Now our Next.js project structure looks like this:

  • Run your Next.js app in development environment with dev server (with hot loading feature)
$ npm run dev
  • Or run the app in production environment with production server (without hot loading feature)
$ npm run build
$ npm run start
  • Create app pages and fetch data via Rest API

In Next.js, a page is a React Component in the pagesdirectory. Each page is associated with a route based on its file name. I have created about page, blog page, and works page like below.

Here is what does /pages/blog/index.js look like in my project:

All the async functions associated with API are defined inside a separate file /lib/api.js

We fetch data by calling the API inside getStaticProps from page component, as Next.js will pre-render this page at build time using the props returned by getStaticProps. In our case, the props with data from our Rest API.

The data will be displayed in the web page. And we can see the blog page from this URL: http://localhost:3001/blog

If trying to open other non-existing pages, Next.js’s default 404 page will show up (we are allowed to customised this error page)


This post has briefly walked you through the development process of building a full-stack web application with Next.js and Strapi V4. If you don’t bother dealing with database, building your own Rest API using frameworks like Django, Express, Spring boot, etc., you could simply define the Content Type inside Strapi and let Strapi automatically generate the API for you like I did for this project. It saves tons of time. Especially if your project is something like a blog website or other media websites, the CMS coming out of Strapi comes in handy by providing you a nice user interface to write, schedule and publish content, as well as managing multiple content authors for you.

Although I use Next.js and Strapi V4 for this relative small blog website, you could definitely expand its usage to other interesting projects. Both technologies have very nice documentation, and you can find tons of good use cases (how to implement in a real project) on their websites in order to help you get a quick start.

A software project can only be impactful if we deploy it to hosting services to make it public. Therefore, in the next post, I will walk you through how I deploy both front end and back end to two separate hosting services — Vercel (Next.js app as client ) and DigitalOcean (Strapi V4 app as backend).



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store