Most WordPress sites in 2026 don’t need to be headless. A well-tuned classic WP install with a fast theme, WPRocket and Cloudflare in front will hit 80-90 on PageSpeed and serve most Indian SMBs perfectly well. Headless is the right answer in maybe 1 in 5 cases — but when it is right, the gains are real: 100/100 Lighthouse, sub-second loads on Indian 4G, a front-end you can iterate without breaking WordPress, and editors who keep using the Gutenberg interface they already know.
This is what we’ve learned shipping 8 headless WordPress + Next.js sites for Indian heritage brands, news verticals, D2C stores and a couple of fintech blogs.
कब When headless is the right call (and when it isn’t)
Build headless when:
- SEO Core Web Vitals are make-or-break — competitive search markets, Google Discover, news/editorial. Sub-second LCP genuinely moves rankings in 2026.
- You need a custom front-end — product configurator, interactive booking flow, custom e-commerce checkout, a SaaS dashboard adjacent to the marketing site.
- You want to scale rendering independently of editorial CMS — CDN-cached, edge-rendered Next.js can survive a 50k concurrent burst that would melt a single WP server.
- You’re planning to migrate off WordPress eventually but want editors to keep using Gutenberg in the interim. Headless is the cleanest exit ramp.
Don’t build headless when:
- Site is < 30 pages, mostly static brochure content, no growth plans — the operational complexity isn’t worth it.
- You have a heavy WooCommerce dependency — the headless Woo story (Faust + WooGraphQL) works but is rougher than classic Woo. You’ll spend weeks rebuilding checkout. Use classic Woo unless you have a strong reason.
- Editors need to drag-and-drop with Elementor / Divi visual builders — those builders don’t headless cleanly. Gutenberg blocks do.
- Your team can’t maintain two stacks. Headless means WP plus Next.js plus a build pipeline plus two hosts. If that scares you, classic WP with WPRocket is fine.
वास्तुकला The architecture — what lives where
The fundamental split: WordPress is the editor + database; Next.js is the renderer.
┌─────────────────────────┐ ┌─────────────────────────┐
│ WordPress (admin) │ │ Next.js (public) │
│ │ │ │
│ • wp-admin │ │ • SSG for static │
│ • Gutenberg editor │──────▶│ • ISR for blog posts │
│ • WPGraphQL endpoint │ │ • SSR for dynamic │
│ • ACF custom fields │ │ • API routes for forms │
│ • Yoast SEO data │ │ │
│ • Media library │ │ Hosted on Vercel / │
│ │ │ VPS / Cloudflare Pages │
│ Hosted on VPS │ │ │
│ (Hetzner ₹400/mo) │ └─────────────────────────┘
└─────────────────────────┘
↑ wp-admin.yoursite.com ↑ yoursite.com
Editors hit wp-admin.yoursite.com, do their work in Gutenberg + ACF, and click Publish. WordPress fires a webhook to a Vercel deploy hook (or a self-hosted Next.js rebuild). Within 60 seconds, the rendered HTML on yoursite.com updates.
सेटअप The setup — step by step
1. Install the headless plugins on WordPress
WPGraphQL— exposes WordPress as a GraphQL endpoint at/graphql. Faster than REST, lets you query only the fields you need.WPGraphQL for ACF— if you use Advanced Custom Fields (you will).WPGraphQL for Yoast SEO(or RankMath equivalent) — exposes meta titles, descriptions, OG images, JSON-LD via GraphQL.Faust.jscompanion plugin — if you go with Faust framework. Optional; we usually skip it and use vanilla Next.js + WPGraphQL.Headless Modeplugin — redirects the public-facing WordPress URLs to your Next.js frontend, so editors don’t accidentally sharewp-admin.yoursite.com/sample-postinstead of the canonical URL.
2. Set up Next.js with WPGraphQL queries
In Next.js (App Router, 2026):
// app/blog/[slug]/page.tsx
import { gql, getClient } from '@/lib/wpgraphql'
import parse from 'html-react-parser' // safer than raw HTML injection
export async function generateStaticParams() {
const { posts } = await getClient().query({
query: gql`{ posts(first: 100) { nodes { slug } } }`
})
return posts.nodes.map((p) => ({ slug: p.slug }))
}
export const revalidate = 60 // ISR — re-render at most once per minute
export default async function Post({ params }) {
const { post } = await getClient().query({
query: gql`
query Post($slug: ID!) {
post(id: $slug, idType: SLUG) {
title
content
seo { fullHead schema { raw } }
}
}`,
variables: { slug: params.slug }
})
// html-react-parser sanitizes and converts to React elements —
// preferred over dangerouslySetInnerHTML.
return {parse(post.content)}
}
3. Pick a rendering strategy per route
- Static (SSG): About, Contact, marketing pages that change weekly. Built at deploy time, served from CDN. Fastest.
- Incremental Static Regen (ISR): Blog posts, news articles. Built at deploy + re-rendered every 60s if a request comes in. Best of static + fresh.
- Server-side (SSR): User-specific pages, dashboard. Slower, only when needed.
- On-demand revalidation: WordPress hits a webhook on publish → Next.js calls
revalidatePath()→ that one URL re-renders immediately. Best for breaking news.
4. Handle WordPress preview
When an editor clicks “Preview” in Gutenberg, they expect to see the draft on the live site. In headless that’s harder.
// app/api/preview/route.ts
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
export async function GET(req) {
const { searchParams } = new URL(req.url)
if (searchParams.get('secret') !== process.env.PREVIEW_SECRET) {
return new Response('Forbidden', { status: 403 })
}
draftMode().enable()
redirect(`/blog/${searchParams.get('slug')}?preview=true`)
}
In WordPress, override the preview URL: add_filter('preview_post_link', ...) to point at https://yoursite.com/api/preview?secret=X&slug=Y. The endpoint sets a draft cookie, Next.js sees it on the next request, fetches unpublished posts via authenticated WPGraphQL.
5. Image pipeline
WordPress’s media library is fine for editorial use. But you want Next.js to optimise the images, not WP. Use next/image with a custom loader that points at wp-admin.yoursite.com/wp-content/uploads/... — Next.js will pull the original, resize and cache for you.
Or use a CDN like Cloudinary / imgix / Bunny.net in front of WP uploads. We use Cloudflare Images on most projects (₹400/month for 100K-image quota).
तेज़ Hitting 100/100 Lighthouse — the actual checklist
- Self-host fonts via
next/font/google. Zero render-blocking CSS for fonts. - Preload the hero image with
<link rel="preload" as="image">. Cuts LCP by 200-400ms on Indian 4G. - Use Next.js Image with explicit width & height — prevents CLS, lazy-loads off-screen images.
- Inline critical CSS — Next.js does this automatically with
app/router. - Strip unused JS — don’t ship the Apollo client to a static page that has no client-side queries; use server-component fetch instead.
- Set Cache-Control headers on static assets —
public, max-age=31536000, immutable. - Cloudflare in front with “Cache Everything” rule for HTML on static routes (be careful with cookies/dynamic).
- Audit third-party scripts — analytics, intercoms, chat widgets. They’re the #1 reason WordPress sites don’t hit 100 LH.
गलतियाँ Gotchas we’ve hit (so you don’t)
- Internal links break on migration — WordPress stores internal links as full URLs (
https://yoursite.com/blog/foo). When you switch domains for the WP admin, those links still point at the old URL. Fix with a search-and-replace on publish, or a regex on render. - Yoast XML sitemap is at the wrong URL — Yoast generates it at
wp-admin.yoursite.com/sitemap_index.xml. Google needs it atyoursite.com/sitemap.xml. Generate your own in Next.js using WPGraphQL queries. - WPGraphQL N+1 queries — if you query a post and then its 50 comments and each comment’s author, you can issue 100+ DB queries per page. Use
resolversor batch-load via DataLoader. CheckQueryMonitorplugin on the WP side. - Editor confusion about “where is the site?” — we put a banner in wp-admin saying “Public site lives at yoursite.com — this is the editor only.”
- Plugin compatibility — ~20% of WP plugins don’t fully headless. Contact form 7, Mailchimp form, anything that injects script tags into post content — you may have to reimplement in Next.js.
मेज़बानी Hosting in India — what we actually use
| Component | Recommendation | Monthly cost |
|---|---|---|
| WordPress (editor) | Hetzner Cloud CPX11 or DigitalOcean Bangalore droplet, 2GB RAM | ₹400-600 |
| Next.js (public site) | Vercel Hobby (free for low traffic) or self-host on same VPS | ₹0 - ₹1700 |
| CDN / DNS | Cloudflare free tier; add Pro if you need image optimisation | ₹0 - ₹1700 |
| Database backups | Cron + S3-compatible storage (Backblaze B2) | ~₹100 |
| Email (transactional) | Brevo / Mailgun free tier | ₹0 initially |
For most Indian SMB sites, ~₹700-1000/month is realistic landed cost — cheaper than the equivalent shared-hosting WordPress with premium theme + WPRocket + Cloudflare Pro stack.
Headless WordPress isn’t a religion. It’s a sharp tool that’s right for ~20% of WP sites and overkill for the rest. Pick it when SEO is a moat, when you need a custom front-end, or when you’re planning an eventual migration off WP. Otherwise, classic WordPress is just fine.
If you need help
We do custom WordPress development in both modes — classic and headless. If you’re not sure which you need, we’ll tell you honestly in the scoping call. Free written quote within 24 hours, source code on your GitHub from day one, 3 months of free post-launch support. Tell us about your site.
Ramesh Patel is Principal Engineer at Antarix Technology. 15 years building production web infrastructure — previously at Flipkart and Stripe. He’s shipped 8 headless WP sites and migrated 4 large WordPress installs to modern stacks. Reach him on WhatsApp or info@antarixtech.com.