
Headless WordPress Without GraphQL: A Simpler, Faster Approach
The GraphQL Elephant in the Room
Ask any developer about headless WordPress, and you’ll hear the same advice: “Use WPGraphQL.”
It’s become the default recommendation—so ubiquitous that many developers assume GraphQL is required for headless WordPress. But here’s a question nobody asks:
Do you actually need GraphQL?
For 95% of headless WordPress projects—blogs, marketing sites, portfolios, documentation—the answer is no. And forcing GraphQL into these projects adds complexity, performance overhead, and maintenance burden that simply isn’t justified.
This article explores an alternative: headless WordPress without GraphQL. Simpler. Faster. Just as capable for content-driven sites.
Why GraphQL Became the Default
GraphQL was invented by Facebook in 2012 to solve a specific problem: mobile apps needed to fetch complex, nested data structures with minimal bandwidth. Instead of making 10 API calls, you could make one GraphQL query and get exactly what you need.
For Facebook’s use case—millions of mobile users fetching deeply nested social graphs—GraphQL was revolutionary.
WordPress is not Facebook.
When WPGraphQL brought this technology to WordPress, it promised the same benefits:
- Fetch only the fields you need
- Reduce over-fetching
- Get related data in one request
- Modern developer experience
The WordPress community embraced it enthusiastically. Finally, a “modern” API!
But in practice, WPGraphQL creates problems that didn’t exist before.
The Hidden Costs of GraphQL in WordPress
1. Query Complexity Overhead
Every GraphQL request requires:
- Parsing the query string
- Validating against the schema
- Resolving field dependencies
- Executing nested resolvers
- Assembling the response
This happens on every request. For a simple blog post fetch, WPGraphQL runs 12+ database queries and takes 300-800ms to respond.
# A "simple" query for 10 blog posts
query {
posts(first: 10) {
edges {
node {
title
excerpt
featuredImage {
node {
sourceUrl
}
}
author {
node {
name
}
}
}
}
}
}
This query looks clean, but under the hood, WPGraphQL is:
- Querying posts table
- Querying postmeta table
- Querying users table
- Querying attachments table
- Resolving each relationship separately
- Formatting nested JSON output
Result: 500ms+ response time for data that doesn’t change between requests.
2. The N+1 Query Problem
GraphQL’s nested resolver pattern creates the infamous N+1 problem. Fetch 10 posts with authors, and you might run:
- 1 query for posts
- 10 queries for authors (one per post)
- 10 queries for featured images
- 10+ queries for categories
WPGraphQL uses DataLoader to batch some queries, but it can’t eliminate the problem entirely. Complex pages with related content can trigger 50+ database queries per request.
3. Schema Maintenance Burden
GraphQL requires a schema. WPGraphQL generates one from your WordPress data, but any customization requires:
- Custom types
- Custom resolvers
- Custom connections
- Testing for breaking changes
Add ACF, custom post types, or third-party plugins? You’ll need extensions:
- WPGraphQL for ACF
- WPGraphQL for Yoast
- WPGraphQL for WooCommerce
- WPGraphQL for [every plugin]
Each extension adds complexity and potential points of failure.
4. Learning Curve for Teams
Your content editors don’t care about GraphQL—they just want WordPress to work. But your developers now need to:
- Learn GraphQL syntax
- Understand WPGraphQL’s WordPress-specific implementation
- Debug nested resolver issues
- Manage query complexity limits
- Handle GraphQL-specific error patterns
For a blog? This is massive overkill.
5. Caching Challenges
REST APIs are easy to cache. Each endpoint has a predictable URL:
GET /wp-json/wp/v2/posts/123
GraphQL uses a single endpoint for everything:
POST /graphql
Every request is a POST with a unique query body. Traditional HTTP caching doesn’t work. You need:
- Persisted queries
- Response caching layers
- Cache invalidation logic
- WPGraphQL Smart Cache (another plugin)
More complexity. More moving parts.
The Alternative: Pre-Compiled REST
What if you could have the performance benefits without the GraphQL complexity?
The insight: Blog content doesn’t change at request time. It changes when an editor clicks “Save.”
Instead of computing API responses on every request, pre-compile them once when content is saved. Then serve the pre-compiled JSON directly—no query resolution, no nested lookups, no overhead.
How Pre-Compilation Works
Traditional approach (WPGraphQL/REST):
- Request arrives
- Parse query/parameters
- Execute 10-50 database queries
- Resolve relationships
- Format response
- Return JSON
- Time: 300-800ms
Pre-compiled approach (Headless Bridge):
- Editor saves content in WordPress
- Background process compiles full JSON response
- Stores flat JSON in database
- Request arrives
- Fetch pre-compiled JSON (1 indexed query)
- Return JSON
- Time: 30-60ms
The computation happens once, at save time. API requests become simple database lookups.
Performance Comparison
Real benchmarks from identical test environments:
Single Post Fetch (10,000 posts in database)
| Metric | WPGraphQL | REST API | Headless Bridge |
|---|---|---|---|
| TTFB | 847ms | 512ms | 51ms |
| DB Queries | 14 | 9 | 1 |
| Response Size | 16.2KB | 12.5KB | 8.4KB |
| CPU Usage | 65% | 45% | 6% |
List Endpoint (Fetch 20 Posts)
| Metric | WPGraphQL | REST API | Headless Bridge |
|---|---|---|---|
| TTFB | 920ms | 685ms | 62ms |
| DB Queries | 48 | 42 | 1 |
| Requests/sec | 8.7 | 12.3 | 287.5 |
Bottom line: Pre-compiled REST is 10-15x faster than GraphQL for typical content fetches.
When GraphQL Makes Sense (And When It Doesn’t)
Use GraphQL When:
✅ Building complex applications with dynamic queries (e-commerce filtering)
✅ You need real-time data that changes per request
✅ Multiple frontends need different data shapes
✅ Your team already knows GraphQL deeply
✅ You’re building admin dashboards or internal tools
Skip GraphQL When:
✅ Building blogs, marketing sites, portfolios
✅ Content is primarily static (changes on save, not per-request)
✅ Performance and Core Web Vitals matter
✅ You want simpler architecture
✅ You’re budget-conscious on hosting
✅ Your team is small or non-technical
The honest truth: 95% of headless WordPress sites are content sites. They don’t need GraphQL’s query flexibility—they need speed and simplicity.
Building Headless WordPress Without GraphQL
Here’s how to build a fast headless WordPress site without touching GraphQL:
Step 1: Choose Your API Approach
Option A: WordPress REST API (Built-in)
- Already installed in every WordPress site
- Simple and well-documented
- Works but has performance limitations at scale
Option B: Pre-Compiled API (Recommended)
- Install a plugin like Headless Bridge
- Get sub-100ms response times
- No GraphQL learning curve
- Works with any frontend framework
Step 2: Install Headless Bridge
# Via WordPress admin
Plugins → Add New → Search "Headless Bridge" → Install → Activate
# Or via WP-CLI
wp plugin install headless-bridge --activate
Step 3: Configure Your API
Navigate to Headless Bridge → Settings:
- Enable API endpoints
- Configure rate limiting
- Generate API key (optional)
- Click “Recompile All Content”
Step 4: Fetch Data in Your Frontend
Next.js:
// lib/api.ts
const API_URL = process.env.NEXT_PUBLIC_WP_API;
export async function getPosts() {
const res = await fetch(`${API_URL}/pages?type=post`);
return res.json();
}
export async function getPost(slug: string) {
const res = await fetch(`${API_URL}/page?slug=${slug}`);
return res.json();
}
React:
// hooks/usePosts.ts
import { useState, useEffect } from 'react';
export function usePosts() {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch(`${API_URL}/pages?type=post`)
.then(res => res.json())
.then(data => setPosts(data.pages));
}, []);
return posts;
}
Astro:
---
// src/pages/blog/[slug].astro
export async function getStaticPaths() {
const res = await fetch(`${import.meta.env.WP_API}/pages?type=post`);
const data = await res.json();
return data.pages.map(post => ({
params: { slug: post.slug },
props: { post }
}));
}
const { post } = Astro.props;
---
<article>
<h1>{post.title}</h1>
<div set:html={post.content} />
</article>
Step 5: Deploy
Deploy your frontend to:
- Vercel (recommended for Next.js)
- Netlify
- Cloudflare Pages
- Any static hosting
Your WordPress backend stays where it is. API requests are lightning fast.
Migration: From WPGraphQL to REST
Already using WPGraphQL? Migration is straightforward:
1. Install Headless Bridge Alongside WPGraphQL
Run both during transition. Headless Bridge uses different endpoints (/bridge/v1/) so there’s no conflict.
2. Update Frontend Queries
Before (WPGraphQL):
const GET_POSTS = gql`
query GetPosts {
posts(first: 10) {
edges {
node {
title
slug
excerpt
}
}
}
}
`;
const { data } = await client.query({ query: GET_POSTS });
const posts = data.posts.edges.map(edge => edge.node);
After (Headless Bridge):
const res = await fetch(`${API_URL}/pages?type=post&limit=10`);
const data = await res.json();
const posts = data.pages;
Simpler code. Faster results. No GraphQL client needed.
3. Update Field Mappings
| WPGraphQL | Headless Bridge |
|---|---|
post.title | post.title |
post.content | post.content |
post.featuredImage.node.sourceUrl | post.featuredImage.url |
post.author.node.name | post.author.name |
post.seo.metaDesc | post.seo.description |
Headless Bridge uses flat JSON—no more .node or .edges wrappers.
4. Test and Remove WPGraphQL
Once your frontend is fully migrated:
- Run side-by-side for a week
- Verify all pages render correctly
- Deactivate WPGraphQL
- Enjoy faster sites and simpler code
Real-World Results
Case Study: Tech Blog (50,000 posts)
Before (WPGraphQL):
- TTFB: 1,200ms average
- Lighthouse Performance: 68
- Monthly hosting: $200/month
- Frequent timeout errors during traffic spikes
After (Headless Bridge):
- TTFB: 55ms average
- Lighthouse Performance: 98
- Monthly hosting: $50/month
- Zero timeouts, handles 10x traffic
Case Study: Marketing Agency (12 client sites)
Before:
- Each client site used WPGraphQL
- Developers spent hours debugging GraphQL issues
- Client complaints about slow preview
After:
- Switched all sites to Headless Bridge
- API integration time dropped from 2 days to 2 hours
- Clients happy with fast previews
Common Objections (Answered)
“But GraphQL lets me fetch exactly what I need!”
In theory. In practice, most content sites fetch the same data on every page. The “flexibility” of GraphQL becomes a maintenance burden when you could just have one optimized endpoint.
“Won’t pre-compiled responses get stale?”
Headless Bridge recompiles automatically when you save content. There’s a 5-30 second delay while background processing runs. For most content sites, this is invisible.
“What about complex queries?”
If you genuinely need complex, dynamic queries (e-commerce filtering, search facets), GraphQL might still make sense. But for content delivery? Pre-compiled wins every time.
“Everyone uses WPGraphQL. Isn’t that the standard?”
Popularity doesn’t equal fit. WPGraphQL is excellent for certain use cases. But defaulting to it for every project adds unnecessary complexity. Choose the right tool for your needs.
Conclusion
GraphQL is a powerful technology—for the right problems. But headless WordPress doesn’t automatically require GraphQL.
For content-driven sites (which is most of them), a pre-compiled REST approach delivers:
- 10-15x faster response times
- Simpler frontend code
- Lower hosting costs
- Easier maintenance
- Better Core Web Vitals
Don’t add complexity you don’t need. Build fast, simple, maintainable headless WordPress sites without GraphQL.
Try It Yourself
Free Download: wordpress.org/plugins/headless-bridge-by-crux
5-Minute Test:
- Install Headless Bridge
- Click “Recompile All Content”
- Open browser:
https://yoursite.com/wp-json/bridge/v1/pages?type=post - See the difference
Questions? email support@headless-bridge.com
Last updated: February 2026