← All writingStudio / Why I Rebuilt My Portfolio in Astro Instead of Next.jsMuntahi Safwan
Studio · 3 min read ·

Why I Rebuilt My Portfolio in Astro Instead of Next.js

I rebuilt this site in Astro because a portfolio is mostly content, and Astro sends plain HTML with no JavaScript unless you ask for it. The move alone did not make the site fast, though. The mobile Lighthouse score started at 43, and getting it to 81 came from fixing four specific problems that had nothing to do with the framework.

My previous portfolio was a Next.js 14 app with React, Framer Motion and a particle library. It worked, but every visitor downloaded a framework before they saw my name.

Why Astro for a portfolio?

A portfolio is pages of text and images with a few interactive moments. Astro treats that as the default case. Each page is built to static HTML, and scripts are added only where I want them. Search engines and AI assistants read the page without running anything, which matters because many of those crawlers do not execute JavaScript at all.

It also let me keep writing in Markdown. Articles and case studies live as files in the repository, and I edit them through Keystatic, a free admin dashboard that saves straight back to those files. There is no database to run.

Next.js is a good tool. I use React at work. It is simply built for applications, and this is a document.

What made the first version slow?

The new site is animation-heavy. It has a split hero, a portrait drawn in code, device photos that zoom on scroll and a skills map. On a desktop it scored in the nineties. On a simulated mid-range phone it scored 43, with almost three seconds of blocking time.

Four things were responsible.

The first was a font animation that never stopped. On touch screens the letters of my name gently changed weight using the variable font. That looks harmless, but changing a font's weight forces the browser to lay out the page again, and it was doing so about twenty times a second, forever, even when the hero was off screen.

The second was that every section set itself up at once. Around twenty-five pieces of the page initialised in a single burst when the script loaded, and the phone froze until they finished.

The third was that the hero waited for its own intro. The headline and portrait were hidden until an opening animation completed, so the largest element on the page painted late.

The fourth was blend modes. Paper grain, the navigation and large titles all used blending effects, which made the browser recomposite big areas on every scroll frame.

What fixed it?

I removed the font animation on phones. Sections now initialise one after another with a pause between each, so the page can paint and respond first. On small screens the hero is complete on first paint, and the code portrait is a pre-rendered image instead of something the phone computes. The grain became a plain texture, and background videos play only while they are on screen.

After those changes the mobile score was 81, blocking time fell from about 2,940 milliseconds to around 150, and the desktop score was 92. Layout work on the main thread dropped from 3.7 seconds to 1.3.

What I would tell someone doing the same

Pick the framework that matches the shape of the thing you are building. Then measure on a slow phone, because that is where the truth is. Most of my problems were not JavaScript at all. They were the browser repainting and re-laying-out things I had asked it to animate, and a profiler found them faster than guessing ever would have.

The site still has room to improve. The two serif font files are heavier than I would like. But it loads quickly, it reads cleanly to a crawler, and I can publish a post by saving a file.

Written by Muntahi Safwan, founder of Octarnal, a software agency in Dhaka, and a Computer Science and Engineering student at AIUB.