Why I Chose Next.js for My Frontend

By Yusuf Setiyawan
Picture of the author
Published on
Next.js Frontend Development

When I started building Ruang Bimbel, I had to make an important decision: which frontend framework should I use? After evaluating several options, I chose Next.js — and it turned out to be one of the best decisions for the project.

Here's my journey and why Next.js won.


The Landscape of Frontend Frameworks

The JavaScript ecosystem is overwhelming. Every week, there's a new framework promising to solve all your problems. When I started, my shortlist looked like this:

  • Create React App — The classic choice
  • Vite + React — Lightning-fast development
  • Next.js — Full-featured React framework
  • Remix — The new kid on the block
  • Vue/Nuxt — A completely different ecosystem

Each has its merits, but I needed something specific for an EdTech platform with multiple apps.


Why Next.js?

1. File-Based Routing That Just Works

No more configuring React Router. With Next.js, your file structure IS your routing:

pages/
├── index.tsx          → /
├── about.tsx          → /about
├── exams/
│   ├── index.tsx      → /exams
│   └── [id].tsx       → /exams/:id
└── dashboard/
    └── [...slug].tsx  → /dashboard/*

For Ruang Bimbel with its complex routing (user dashboard, admin panel, exam pages), this was a game-changer.

2. Server-Side Rendering (SSR) Out of the Box

EdTech platforms need good SEO. Students searching for "tryout CPNS online" should find us. With Next.js, SSR is as simple as:

export async function getServerSideProps() {
  const exams = await fetchExams()
  
  return {
    props: { exams }
  }
}

export default function ExamsPage({ exams }) {
  return (
    <div>
      {exams.map(exam => (
        <ExamCard key={exam.id} exam={exam} />
      ))}
    </div>
  )
}

The page is rendered on the server, fully indexed by search engines, and fast for users.

3. Static Generation for Speed

Not everything needs to be dynamic. Landing pages, blog posts, and documentation can be statically generated at build time:

export async function getStaticProps() {
  const posts = await fetchBlogPosts()
  
  return {
    props: { posts },
    revalidate: 3600 // Regenerate every hour
  }
}

The result? Blazing fast page loads and lower server costs.

4. API Routes — Backend in Your Frontend

Need a quick API endpoint? Just create a file in pages/api/:

// pages/api/contact.ts
export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' })
  }
  
  const { email, message } = req.body
  await sendEmail({ email, message })
  
  res.status(200).json({ success: true })
}

For Ruang Bimbel's landing page, I use API routes for contact forms and newsletter subscriptions. No need to spin up a separate backend for simple things.

5. Image Optimization Built-In

Images are often the biggest performance killer. Next.js's Image component handles everything:

import Image from 'next/image'

<Image
  src="/hero.jpg"
  alt="Hero image"
  width={1200}
  height={600}
  priority
/>

It automatically:

  • Serves WebP/AVIF when supported
  • Lazy loads images below the fold
  • Prevents layout shift
  • Resizes for different devices

6. TypeScript First-Class Support

Just rename your files to .tsx and you're done. No complex configuration:

interface Exam {
  id: string
  title: string
  duration: number
  questions: Question[]
}

interface Props {
  exam: Exam
}

export default function ExamPage({ exam }: Props) {
  // Full type safety
}

The Power of TanStack Query

Next.js handles the framework side, but for data fetching and caching on the client, I pair it with TanStack Query (formerly React Query):

function useExams() {
  return useQuery({
    queryKey: ['exams'],
    queryFn: fetchExams,
    staleTime: 5 * 60 * 1000, // 5 minutes
  })
}

function ExamsPage() {
  const { data: exams, isLoading, error } = useExams()
  
  if (isLoading) return <Skeleton />
  if (error) return <ErrorMessage error={error} />
  
  return <ExamList exams={exams} />
}

The combination gives you:

  • Automatic caching and background refetching
  • Optimistic updates
  • Infinite scrolling with ease
  • DevTools for debugging

Managing 4 Frontend Apps

For Ruang Bimbel, I actually run 4 separate Next.js applications:

  1. Landing App — Marketing and public pages
  2. User App — Student learning platform
  3. Admin App — Content management
  4. Super Admin App — System administration

Each is its own Next.js project, but they share:

  • Common UI components (via a shared package)
  • Type definitions (shared TypeScript types)
  • API client (shared fetch utilities)

This separation gives me:

  • Independent deployments
  • Different caching strategies per app
  • Cleaner codebase for each concern

What I Don't Love

No framework is perfect. Here's what sometimes frustrates me:

  1. Build times — Large apps can have slow builds. Turbopack helps, but it's still in beta.
  2. Complexity — The App Router vs Pages Router confusion is real. I stick with Pages Router for now.
  3. Vercel lock-in concerns — While Next.js works anywhere, some features are Vercel-optimized.
  4. Bundle size — You need to be careful about what you import.

Alternatives I Considered

Vite + React:

  • ✅ Faster development server
  • ❌ No built-in SSR
  • ❌ More configuration needed

Remix:

  • ✅ Great data loading patterns
  • ✅ Progressive enhancement
  • ❌ Smaller ecosystem
  • ❌ Less mature

Create React App:

  • ✅ Simple to start
  • ❌ No SSR
  • ❌ Officially deprecated-ish

My Recommendations

Choose Next.js if:

  • SEO matters for your application
  • You want a batteries-included framework
  • You need SSR/SSG/ISR flexibility
  • You're building a production-grade app

Consider alternatives if:

  • You're building a simple SPA with no SEO needs
  • You want maximum control over everything
  • Bundle size is your primary concern

Final Thoughts

Next.js has been the backbone of Ruang Bimbel's frontend for months now, and I couldn't be happier. The developer experience is excellent, the performance is great, and the ecosystem keeps getting better.

Combined with TypeScript for type safety and TanStack Query for data management, it's a powerful stack that scales from side projects to production applications.

If you're starting a new project and need SSR, good SEO, and a mature ecosystem — give Next.js a try.


Building something with Next.js? Have questions about my setup? Feel free to reach out!