This was the original iteration of my personal portfolio website. Read here on why I moved away from it.

At the time, I created this site to address some problems I had been having:

  • Aside from GitHub, I did not have a portfolio to show my skills, notable projects, or ways to contact me
  • I didn't have anywhere to deploy, access, and test out different ideas or projects at a centralised domain

This was also a good opportunity for me to reinforce concepts of web design and development and learn new things. Of course, it's easy enough to use a service such as Squarespace to create a website or simply use GitHub as a portfolio, but I wanted to stay away from 'cookie-cutter' approaches as they did not feel as personal.

I could have also achieved this site with a primitive stack, but I decided to overcomplicate it for the sake of learning and some future-proofing: keep reading to find out exactly how I went about making this website, including some of the problems I had and what I did to overcome them!


I wanted to be able to upload, edit and delete projects without touching any code - so I decoupled the backend and frontend by using a headless CMS. I opted for Strapi because it had some good documentation and was completely open-source, meaning there was plenty of community support and most importantly: it's free! Strapi allows me to upload, edit and delete projects through an online panel which is very similar to WordPress. This way, I'm able to add new projects in the future and delete them from practically any device with an internet connection and a browser. It serves this data through REST API endpoints, which are fetched by the frontend to populate the site with data.

One important thing to note is that using the default media library can cause problems where it is wiped on every deployment. To deal with this I changed the default media uploader to Cloudinary using strapi-provider-upload-cloudinary.

Using Strapi in the development phase was extremely easy, with hardly any issues setting it up. It's probably because my use case for this project was very simple, and so not much configuration was needed - just a simple project Content-Type with the relevant fields for data.


Next.js is a React framework that allows for static site generation and comes bundled with extra features like routing and image optimisation. React is becoming my comfort zone as time goes on, and it only felt right to use it for the frontend of my portfolio site. Data fetching is also made very simple using functions like GetStaticProps, which in conjunction with dynamic routing made having unique pages for projects very simple. As the site is statically generated, it is built upon deployment into HTML which makes for an extremely smooth SEO experience as well as being incredibly fast.

One problem I encountered was styling not loading immediately. Instead, unstyled text would be rendered first before firing off transitions to what the text should actually look like. This can be seen in the gif below (turn your brightness up):


This turned out to be a bug with Chrome itself, and after finding an odd but working solution on Stack Overflow, I was able to implement it into a _document.js file like so:

import Document, { Html, Head, Main, NextScript } from "next/document";

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
          <meta charSet="utf-8" />
          <Main />
          <NextScript />
          <script> </script>


For the styling, I decided to try out using Tailwind CSS. Once a system of ordering ClassName values is set along with extending the original config, it became pretty maintainable (providing everything is sensibly compartmentalised into respective components). It's also worth noting that Tailwind has some very detailed documentation, although it needs work in some places (mainly in extending config for certain elements).


For the backend, I hosted Strapi on Heroku using the free hobby plan along with PostgreSQL to store the data. I ran into quite a few errors with deployment here, due to Heroku outputting some weird errors about SSL but these were fixed quickly, as it seemed to be a common problem. However, compared to other CMS options like Forestry, there was definitely a lack of easy deployment options.

With the frontend, I deployed my Next.js project on Vercel. This was probably the quickest deployment process I've encountered so far - mainly because the framework is created by Vercel, and it's clear they've optimised the deployment platform for it.

Both parts of the site have automatic deployment based on GitHub repositories, meaning that whenever I push changes to main they immediately begin to rebuild and deploy. On top of that, I used a webhook between Strapi and Vercel which triggers my frontend to be rebuilt every time there is a change in my CMS.

Overall, this was a pretty fun project to get back into web development with! I still have a lot to learn, but I'm excited to move further into some interesting projects.