DEV Community

Cover image for Hire a Next.js developer who can actually ship production
Nayan Kyada
Nayan Kyada

Posted on • Originally published at nayankyada.com

Hire a Next.js developer who can actually ship production

When you hire a Next.js developer, the risk isn't finding someone who claims the skill — it's hiring someone who has only run create-next-app and watched a YouTube tutorial. This guide gives you concrete signals to separate developers who can ship and maintain a production Next.js site from those who cannot.

What a credible portfolio actually looks like

A live URL is the minimum bar, not proof of quality. Ask for three live sites and verify each one yourself before the first call.

Run PageSpeed Insights on each URL. Open pagespeed.web.dev and paste the homepage. You want LCP under 2.5 seconds, CLS under 0.1, and INP under 200 ms on mobile. A developer who genuinely owns the performance of a site will know those numbers without looking. If the sites score in the 40s on mobile, that tells you they shipped something but did not own the outcome.

Check whether the site actually uses the App Router. Open DevTools → Network, hard-refresh, and look at the response headers. An App Router site on Vercel will have x-nextjs-cache headers and typically content-type: text/html for RSC payloads on navigation. Alternatively, just ask: "What version of Next.js is this on, and is it Pages Router or App Router?" A developer who built it will answer immediately.

Look for evidence of CMS integration, not just static sites. A portfolio of five identical blog starters proves nothing. You want at least one site that connects to a real data source — Sanity, Contentful, Payload, a custom API — and shows that they have thought about revalidation strategy (ISR tags, on-demand revalidation, or PPR).

Ask about the worst production bug they fixed. The answer reveals operational maturity. "We had a stale cache after a Sanity publish and had to add tag-based revalidation" is a better signal than "I've never had a bug in production."

App Router literacy check

The Pages Router still works, but any developer you hire in 2026 for a new project should be fluent in the App Router. These questions take under five minutes and filter hard.

"When does a Server Component re-render?" The correct answer: it doesn't re-render on the client at all — it fetches fresh HTML/RSC payload on navigation or after a revalidation event. Someone who says "when the state changes" is thinking in Pages Router terms.

"Where would you put a session cookie read — a Server Component or a Client Component?" Server Component, using cookies() from next/headers. If they reach for useEffect and a client-side fetch, that's a Pages Router reflex.

"What is the difference between revalidatePath and revalidateTag?" revalidatePath purges a specific URL from the cache. revalidateTag purges all cached fetches that were tagged with a given string — more granular and more useful for CMS webhook revalidation. A developer who has wired up a real CMS will know this distinction.

"How would you handle a component that needs both static generation and user-specific data?" The right answer in 2026 is Partial Prerendering: wrap the static shell in a normal async Server Component, put the personalised part behind a <Suspense> boundary, and let Next.js stream it from the edge. Alternatively, route-level SSR with export const dynamic = 'force-dynamic' for simpler cases. If they cannot articulate any of this, they have not shipped PPR or streaming SSR in a real project.

Performance red flags to watch for

These show up in code review or in a short technical conversation.

  • Fetching data inside Client Components with useEffect when a Server Component would do. This pushes network waterfalls onto the browser and increases LCP.
  • No sizes prop on next/image. Every <Image> without a sizes attribute defaults to 100vw, forcing the browser to download a full-width image for a card that is 300 px wide. CLS spikes follow.
  • loading="eager" on every image. This is usually a developer who "fixed" LCP on the hero by removing loading="lazy" globally.
  • No bundle analysis. Ask: "How big is your largest JS chunk and what is in it?" If they have never run @next/bundle-analyzer on a client project, they are shipping blind.
  • Route handlers used where Server Actions would be simpler. Not a hard rule, but it signals they are pattern-matching from Pages Router API routes rather than thinking in RSC architecture.

Rate benchmarks for 2026

Rates vary by region, experience tier, and engagement type. These are honest benchmarks from what I see in the market.

Profile Freelance day rate (USD) Monthly retainer
Junior (1–2 years, Pages Router era) $200–$350 $2,500–$4,000
Mid (2–4 years, App Router production exp.) $400–$600 $5,000–$8,000
Senior (4+ years, performance + CMS depth) $650–$1,000 $9,000–$14,000
Agency team (design + dev + PM) $12,000–$30,000

India-based freelancers typically run 40–60% of the above. That gap is real and the quality range is also wide — the vetting process in this post matters more at that price point, not less, because there are more candidates.

If someone quotes significantly below the junior band and claims senior-level output, ask for a paid two-hour technical task before committing to a project engagement. A small paid test is normal, protects both sides, and tells you more than any interview.

What to send them before the first call

Send a one-paragraph brief: what the site does, rough page count, CMS preference if any, and whether you have an existing codebase or are starting fresh. Then ask them to respond with: their relevant past project (one sentence each), their preferred rendering strategy for this use case and why, and their availability.

The quality of that response — not whether they use the right buzzwords, but whether they ask a clarifying question about your data model or traffic patterns — is the best pre-screening signal you have. Developers who have shipped real projects ask questions. Developers who are guessing give you a generic pitch.

Top comments (0)