DEV Community

Cover image for Why We Built Headless Bridge: The Problem with WPGraphQL
Andy Ryan
Andy Ryan

Posted on • Originally published at headless-bridge.com

Why We Built Headless Bridge: The Problem with WPGraphQL

The Problem That Wouldn't Go Away

It was 2 AM on a Tuesday, and I was staring at my browser's network tab again. The numbers were brutal:

TTFB: 847ms

For the third client project in a row, I was hitting the same wall. The headless WordPress site looked beautiful—modern React frontend, slick animations, perfect design. But the performance? Unacceptable.

"Just use WPGraphQL," everyone said. "It's the standard for headless WordPress."

So we did. And it was killing our Core Web Vitals.

This is the story of why we built Headless Bridge, and why WPGraphQL's approach to headless WordPress APIs is fundamentally flawed for most use cases.


The WPGraphQL Promise (and Reality)

When WPGraphQL launched, it was revolutionary. Finally, a proper GraphQL API for WordPress! No more wrestling with the clunky REST API. You could query exactly what you needed, nest relationships, and build truly decoupled WordPress sites.

The promise was incredible:

  • Query flexibility with GraphQL
  • Fetch only the data you need
  • Reduce over-fetching and under-fetching
  • Modern API for modern frameworks

But the reality was different:

// A simple query to get 10 blog posts
query {
  posts(first: 10) {
    edges {
      node {
        id
        title
        excerpt
        featuredImage {
          node {
            sourceUrl
            mediaDetails {
              width
              height
            }
          }
        }
        author {
          node {
            name
          }
        }
        categories {
          edges {
            node {
              name
            }
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This "simple" query to fetch 10 blog posts would trigger:

  • 12+ database queries
  • 500-800ms TTFB on a decent server
  • 15KB+ response size with deeply nested JSON
  • Performance degradation as content grows

And this was on a good day.


The Day Everything Broke

The turning point came with a high-traffic client project. A content publisher with 50,000+ posts and millions of monthly visitors.

Week 1: Everything seemed fine in development.

Week 2: Staging environment started showing cracks. API responses were hitting 1-2 seconds.

Week 3: Launch day. Within hours, the site was crawling. TTFB spiked to 3+ seconds during peak traffic.

Week 4: Emergency client meeting. "Why is our $50,000 headless WordPress site slower than our old WordPress theme?"

We tried everything:

  • ✅ Enabled object caching (Redis)
  • ✅ Added a CDN
  • ✅ Optimized database queries
  • ✅ Upgraded server resources (3x the cost)
  • ✅ Implemented query complexity limits
  • ✅ Added aggressive GraphQL query caching

Result: Marginal improvement. TTFB dropped from 3 seconds to 800ms. Still terrible.

The client threatened to cancel the project and revert to their old WordPress theme.


Understanding the Core Problem

After weeks of profiling, benchmarking, and digging through WPGraphQL's internals, I finally understood the fundamental issue:

WPGraphQL Computes Everything at Request Time

Every single API request goes through this process:

  1. Parse the GraphQL query (compute cost: ~10-20ms)
  2. Resolve field dependencies (compute cost: ~20-30ms)
  3. Execute multiple database queries (compute cost: ~50-300ms)
  4. Resolve nested relationships (compute cost: ~30-100ms)
  5. Format the nested response (compute cost: ~20-50ms)
  6. Return JSON to client (total: 130-500ms minimum)

Every. Single. Request.

Think about that. Your blog post content doesn't change between requests. Your featured images don't change. Your author names don't change. But WPGraphQL recomputes everything from scratch for every request, as if the data is constantly changing.

It's like going to a restaurant where the chef shops for ingredients, cooks your meal from scratch, and washes dishes after every single order—even though you ordered the same dish as the person before you.


The "Aha!" Moment

I was complaining about this to a friend over coffee when he asked a simple question:

"Why does the API need to compute anything at request time? Your content only changes when an editor hits 'Save', right?"

That's when it hit me.

Blog posts don't change at request time. They change at save time.

What if we pre-compiled the JSON response when content is saved, instead of computing it when requested?

  • ✅ Database queries? Run once at save time.
  • ✅ Field resolution? Run once at save time.
  • ✅ JSON formatting? Run once at save time.
  • ✅ API request? Return pre-compiled JSON. Done in <50ms.

This wasn't a new idea. Static site generators like Gatsby do this. But nobody was doing it inside WordPress for the API layer itself.


Building Headless Bridge

That weekend, I started prototyping.

The core concept was simple:

  1. When you save a post in WordPress, compile the full JSON response in the background
  2. Store it in the database as flat JSON
  3. When an API request comes in, return the pre-compiled JSON directly
  4. Zero computation. Zero nested queries. Zero runtime overhead.

The first benchmark results were shocking:

Metric WPGraphQL Headless Bridge (v0.1)
TTFB 487ms 52ms
DB Queries 12 1
Response Size 15.3KB 8.1KB
Speed Improvement Baseline 9.4x faster

Nearly 10x faster with just a prototype.


The Tradeoffs (And Why They Don't Matter)

Of course, there are tradeoffs. Nothing is free in software.

You Lose Query Flexibility

With WPGraphQL, you can query exactly what you want:

query {
  posts {
    title  # Just the title
  }
}
Enter fullscreen mode Exit fullscreen mode

With Headless Bridge, you get a fixed JSON structure:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "My Blog Post",
  "content": "...",
  "excerpt": "...",
  "featured_image": {...},
  "author": {...},
  "categories": [...]
}
Enter fullscreen mode Exit fullscreen mode

But here's the thing: In practice, 95% of headless WordPress projects use the same standard queries:

  • Get all posts
  • Get single post
  • Get posts by category
  • Get posts by tag
  • Get pages

You almost never need GraphQL's complex querying capabilities. And when you do, you're usually better off implementing that logic in your frontend or using a dedicated search service like Algolia.

Trade query flexibility for 10x performance? That's a deal most developers will take.

Content Updates Aren't Instant

With WPGraphQL, changes appear immediately in the API. With Headless Bridge, there's a small delay (typically 5-30 seconds) while content is recompiled in the background using WordPress's Action Scheduler.

But again: For 99% of content sites, instant updates don't matter. Blog posts, marketing sites, documentation—content changes a few times per day at most. A 10-second delay is totally acceptable in exchange for 10x faster performance.

If you need real-time updates (like a live sports site or stock ticker), Headless Bridge isn't for you. But most sites don't need that.


The Results

I rebuilt that failing client project using the Headless Bridge prototype.

Before (WPGraphQL):

  • TTFB: 847ms average, 3000ms+ at peak
  • Lighthouse Performance Score: 67
  • Server costs: $400/month (upgraded resources to handle load)
  • Client satisfaction: 3/10 (threatening to cancel)

After (Headless Bridge):

  • TTFB: 58ms average, 95ms at peak
  • Lighthouse Performance Score: 98
  • Server costs: $120/month (downgraded back to original resources)
  • Client satisfaction: 10/10 (gave us a testimonial and referred 2 new clients)

The client's exact words: "I don't know what you did, but this is exactly what I wanted from headless WordPress in the first place."


Making It Production-Ready

That prototype worked, but it wasn't production-ready. Over the next few months, we added:

Essential Features

  • Background processing using Action Scheduler (no blocking saves)
  • API key authentication for security
  • Rate limiting to prevent abuse
  • SEO metadata integration (Yoast, RankMath)
  • Image optimization with srcset
  • Multi-language support (WPML, Polylang)
  • UUID-based IDs (no sequential ID leakage)

Advanced Features (Pro)

  • ACF integration for custom fields
  • Webhooks to trigger deploys on Netlify/Vercel
  • Priority support
  • Automatic updates

Performance Optimizations

  • Indexed database queries for sub-50ms response times
  • Flat JSON structure (no nested arrays to parse)
  • Minimal payload size
  • Database-level caching

The Benchmark Data

We ran comprehensive benchmarks against WPGraphQL, REST API, and Headless Bridge across different scenarios:

Scenario 1: Small Site (100 posts)

API TTFB DB Queries Response Size
WordPress REST API 245ms 8 12KB
WPGraphQL 387ms 12 15KB
Headless Bridge 48ms 1 8KB

Scenario 2: Medium Site (10,000 posts)

API TTFB DB Queries Response Size
WordPress REST API 512ms 9 12KB
WPGraphQL 847ms 14 16KB
Headless Bridge 51ms 1 8KB

Scenario 3: Large Site (100,000 posts)

API TTFB DB Queries Response Size
WordPress REST API 1,240ms 11 13KB
WPGraphQL 2,150ms 18 17KB
Headless Bridge 53ms 1 8KB

The key insight: Headless Bridge performance stays flat regardless of content volume. WPGraphQL and REST API degrade significantly.


When You Should (and Shouldn't) Use Headless Bridge

✅ Perfect For:

Content-focused sites - Blogs, marketing sites, documentation, portfolios

  • Content changes occasionally
  • Performance is critical
  • You use Next.js, React, Vue, or similar frameworks

High-traffic sites - News sites, magazines, publishers

  • Millions of requests per month
  • TTFB matters for SEO
  • Server costs matter

Agency projects - Client sites with standard requirements

  • Need ACF integration
  • Want automated deploy webhooks
  • Client expects fast sites

❌ Not Ideal For:

Real-time applications - Live sports scores, stock tickers, chat apps

  • Content changes every second
  • Need instant API updates

Complex data relationships - E-commerce with complex filters

  • Need dynamic querying capabilities
  • Require GraphQL's flexibility

Directory sites - Listings with thousands of search combinations

  • Better served by Algolia or ElasticSearch

The Free vs Pro Decision

We decided to make Headless Bridge free and open source with optional Pro features.

Why free?

  • We wanted to solve the WPGraphQL performance problem for everyone
  • The core technology (pre-compilation) should be accessible
  • Community adoption matters more than short-term revenue

Why Pro?

  • Advanced features (ACF, webhooks) require ongoing maintenance
  • Priority support costs money
  • Sustainable development needs revenue

The split:

  • Free: All core performance features, unlimited API requests
  • Pro ($49.99/year): ACF, webhooks, priority support, auto-updates
  • Agency ($299/year): Unlimited sites, white-label, dedicated support

99% of personal projects can use the free version. Professional projects that need ACF or webhooks upgrade to Pro. Agencies with multiple clients get Agency licenses.


What We Learned

Building Headless Bridge taught us several lessons:

1. Question "Best Practices"

Just because WPGraphQL is the "standard" doesn't mean it's the best solution. Sometimes the best approach is to go back to first principles and rethink the problem.

2. Performance Matters More Than Flexibility

Developers love flexible tools. But users don't care about GraphQL. They care about fast websites. Trade flexibility for performance every time.

3. Pre-compilation > Runtime Computation

For content that doesn't change often, pre-compilation is almost always faster than runtime computation. This applies beyond WordPress APIs.

4. Flat is Better Than Nested

Nested JSON structures are elegant in theory but painful in practice. Flat structures are easier to work with, smaller in size, and faster to parse.


Try It Yourself

Headless Bridge is available now:

Install it, run a benchmark against your current WPGraphQL setup, and see the difference for yourself.


What's Next?

We're actively developing new features:

Coming Soon:

  • Menu endpoint for navigation
  • Global options API for site-wide settings
  • Search integration for Algolia/Meilisearch
  • WooCommerce support (experimental)

On the Roadmap:

  • Custom post type flexibility
  • Multi-site support
  • CDN integration (Cloudflare, Fastly)
  • Analytics dashboard

Want to contribute? Open a GitHub issue or PR. We're building this in public.


Final Thoughts

WPGraphQL is an impressive piece of engineering. For applications that need GraphQL's query flexibility, it's still a solid choice.

But for the vast majority of headless WordPress projects—blogs, marketing sites, documentation, portfolios—you don't need GraphQL's complexity. You need speed.

That's why we built Headless Bridge.

If you're frustrated with slow TTFB, degrading performance at scale, or server costs that keep climbing, give Headless Bridge a try. It might just save your project—like it saved ours.


Ready to 10x your headless WordPress API?

Download Headless Bridge Free →


Questions? Comments? Find me on Twitter @HBridgeWP or email support@headless-bridge.com


About the Author

Andy Ryan is a full-stack developer who specializes in headless WordPress and modern JavaScript frameworks. After years of frustration with WPGraphQL performance, he built Headless Bridge to solve the speed problem once and for all. When not coding, you can find him enjoying nature while rock climbing and hiking.


Related Articles:

Top comments (0)