v/p
Back to blog
Published on

Building a Developer Portfolio with Next.js

A basic summary of how I built this portfolio using Next.js 15, Tailwind CSS v4 and next-intl for bilingual support.

  • Next.js
  • React
  • Tailwind
  • Portfolio

When I decided to rebuild my personal website, I wanted it to reflect how I actually work: fast iteration, good DX, and full TypeScript. Here's what I landed on and why.

The Stack

  • Next.js with the App Router
  • Tailwind CSS using the v4
  • next-intl so I can implement both English and Portuguese content
  • shadcn/ui for accessible, unstyled-first component primitives

Why Next.js App Router?

The App Router changed how I think about React. Server Components let you fetch data directly in the component tree without waterfalls or prop drilling. For a my case, a portfolio, this is more than enough.

// Server Component — no 'use client' needed
export default async function Page({ params }) {
	const { locale } = await params;
	const t = await getTranslations({ locale, namespace: 'Hero' });
 
	return <h1>{t('name')}</h1>;
}

Bilingual Support with next-intl

Supporting Portuguese out of the box was a requirement. next-intl integrates cleanly with the App Router and handles locale detection, URL prefixing and type-safe translation keys.

The key config is localePrefix: 'as-needed'. This way English URLs stay clean (/blog) while Portuguese gets a prefix (/pt/blog). No duplicate content issues, no manual redirects.

Tailwind CSS v4

The v4 migration drops the tailwind.config.js file in favor of CSS-native configuration. Design tokens live in globals.css as @theme blocks.

Lessons Learned

  • Keep section components as Server Components whenever possible to simplify data fetching and reduce bundle size
  • Put all translation strings in JSON files early, even for copy you think won't change
  • Tailwind Typography (@tailwindcss/typography) is worth adding from day one if you plan a blog

The full source is on GitHub.