Building my personal site with Next.js, shadcn/ui, and AI

·4 min read·
#nextjs#shadcn-ui#ai#vercel

Every developer eventually gets around to building their own corner of the web. Mine took a while — not because I lacked the skills, but because the options felt either too heavyweight or too much like starting from scratch. I finally built this site over a weekend, and the combination of tools I used made it surprisingly painless.

Here's what I used and why.


The stack

Next.js (App Router)

I've been working with React for years, so Next.js was a natural choice. The App Router introduced in Next.js 13 makes file-based routing feel genuinely ergonomic — especially for a site like this where I wanted a clean separation between the profile page and a blog.

MDX support is built-in via @next/mdx, which meant blog posts are just markdown files in the app/ directory. No CMS, no database — just files. That suits me well. I can write a post, commit it, and it's live.

shadcn/ui

I picked shadcn/ui because it avoids the usual tradeoff between "install a component library and fight its opinions" and "build everything from scratch." You copy the components you actually need into your own codebase. They're yours — styled with Tailwind, easy to customize, no version conflicts.

The component quality is excellent. Badge, Card, Button, Separator — all the basics are there and well-implemented. I barely had to write any UI primitives.

Tailwind CSS v4

Tailwind v4 ships with a new CSS-first config model. Instead of a tailwind.config.js, you configure your design tokens directly in CSS using @theme. I used the existing shadcn theme which already defines colors in oklch and maps them as CSS variables — it just worked.


Deployment on Vercel

Vercel is where this kind of stack shines. I pushed the repo to GitHub, connected it to Vercel, and got a live preview URL in under two minutes.

Every push to main triggers a new deployment automatically. Preview deployments for feature branches are created automatically too. For a personal site, this is more than enough CI/CD.

The free tier covers everything I need: custom domain, HTTPS, edge CDN, analytics. No infrastructure to manage.


Using GenAI to build it

The honest part: I used an AI coding assistant — specifically Wibey, built on Claude — to help build most of this site.

I didn't prompt it to "build me a portfolio" and paste the output. What I actually did was describe what I wanted in natural language — the sections, the aesthetic (minimal, not resume-y), the data model — and it scaffolded the components, suggested the architecture, and even wrote the first version of this blog post setup.

Here's what surprised me: the quality of the output was high enough that I spent most of my time reviewing and shaping, not fixing. The component structure it suggested — profile data in a single JSON file, typed in TypeScript, consumed by modular section components — was clean. I'd have written something similar myself, but it took seconds instead of an hour.

A few things I adjusted manually:

  • The hero felt too resume-like at first. I asked it to make it more "profile page" and less "CV", and it redesigned the layout — timeline-style experience, friendlier section labels, a pulsing status indicator.
  • I updated the placeholder content in profile.json with real details.
  • I tweaked prose and tone throughout.

The workflow felt collaborative. Not "AI does it, I paste it" — more like pairing with a fast engineer who writes solid first drafts.


Content as data

One deliberate design choice: all profile content lives in src/data/profile.json. Every section — bio, skills, experience, projects — is plain JSON. The React components are just display logic; they don't contain content.

This means updating my profile is a simple JSON edit. No React, no component logic, just data. I've had too many portfolio sites where changing a job title meant digging through a component file.

Blog posts live in src/content/blog/. Each .mdx file carries its own metadata in frontmatter — title, date, description. No separate registry file needed.


What I'd do differently

Add a photo. The avatar is just initials right now. A real photo makes a profile page feel more personal.

Proper OG images. I'd use @vercel/og to generate dynamic open graph images per blog post so links share nicely on social.

RSS feed. A simple route.ts that returns an XML feed of posts. Simple enough to add, I just haven't yet.


The whole thing took a weekend. The stack is boring in a good way — proven tools, zero surprises, fast iteration. And having an AI assistant in the loop made the low-value scaffolding fast enough that I could focus on the parts that actually needed my judgment.

If you're a developer who still doesn't have a personal site: just build it. The barrier is lower than it's ever been.