QTPortfolio
Building a Full-Stack Portfolio with Next.js 14 & Spring Boot
Next.jsSpring BootPostgreSQLFull-Stack

Building a Full-Stack Portfolio with Next.js 14 & Spring Boot

March 15, 20262 min read~295 words

Introduction

Building a personal portfolio is a rite of passage for every developer. But instead of a static site, I wanted something dynamic — a full-stack application with a proper CMS where I can update my projects, skills, and blog posts from an admin dashboard.

Tech Stack Overview

After researching the modern ecosystem, I settled on:

  • Frontend: Next.js 14 (App Router) + Tailwind CSS + shadcn/ui + Framer Motion
  • Backend: Java Spring Boot 3.4.5 + Spring Security + JWT
  • Database: PostgreSQL on Neon (serverless)
  • Deployment: Vercel (frontend) + Fly.io (backend)

Why Next.js App Router?

The App Router in Next.js 14 is a game-changer. Server Components allow us to fetch data on the server without shipping extra JavaScript to the client. This means blazing-fast page loads and excellent SEO — perfect for a portfolio site.

// Server Component — zero client-side JS for data fetching
export default async function HomePage() {
  const posts = await fetchData('/api/blog-posts');
  return <BlogSection posts={posts} />;
}

JWT Authentication with Spring Security

For the admin panel, I implemented JWT-based authentication. The token is stored in an httpOnly cookie — never in localStorage — which prevents XSS attacks from stealing the token.

@PostMapping("/auth/login")
public ResponseEntity<AuthResponse> login(@RequestBody LoginRequest request) {
    // authenticate user
    String token = jwtTokenProvider.generateToken(authentication);
    ResponseCookie cookie = ResponseCookie.from("jwt", token)
        .httpOnly(true)
        .secure(true)
        .path("/")
        .maxAge(Duration.ofDays(7))
        .build();
    return ResponseEntity.ok()
        .header(HttpHeaders.SET_COOKIE, cookie.toString())
        .body(new AuthResponse("Login successful", "admin", "ADMIN"));
}

Eliminating CORS with API Proxy

By configuring Next.js rewrites, all /api/* requests are proxied to the backend. This means the browser only ever talks to Vercel — no CORS configuration needed!

Conclusion

The result is a fast, secure, and maintainable portfolio with a fully functional admin CMS. The separation of concerns between frontend and backend makes it easy to iterate on each independently.

Enjoyed this article?

Share it with your network or explore more posts below.