What Is Headless WordPress (And How Do You Use It)?

Headless WordPress decouples content management from front-end development, enhancing flexibility for developers and businesses.

Mar 20, 2025 - 19:33
 0
What Is Headless WordPress (And How Do You Use It)?

Headless WordPress is transforming how developers and businesses use WordPress by decoupling content management from front-end development.

In a Headless setup, WordPress acts purely as a CMS that exposes content via an API, allowing you to choose any front-end technology to power the user-facing site or app. 

That means you can build a fully static frontend, use server-side rendering, or take a hybrid approach—all using a Headless setup. You can also use any framework or library that can fetch data from an external API, including React, Vue, Astro, Next.js, or a static site generator.

More advanced use cases of Headless WordPress include ecommerce sites, SaaS applications, and mobile apps powered by WordPress. An example you might be familiar with is the Jetpack mobile app.

So how do you know if your project would benefit from a Headless WordPress setup? And how exactly do you connect all the pieces? Read on:

Decoupled, but not disconnected: What is Headless WordPress?

Before we dig deeper, let’s look at how WordPress typically handles a request from a user:

In a traditional environment, WordPress handles the entire stack—content management and the presentation layer.

At a high level, a typical request from a user may look like this:

  • A user requests a page on your website.
  • The request goes to WordPress via NGINX, where we load wp-config, settings, plugins, and the active theme.
  • The requested page/post is determined, and data is queried from the database.
  • From a template hierarchy, the specific templates are determined (page.php, single.php, etc.).
  • The template loads the header, content, footer, and other necessary parts.
  • WordPress outputs the HTML and sends it to the browser, where it is rendered for the user to see and interact with.

There are many similarities between a Headless site and a regular site. However, for a Headless site, your frontend needs to relay requests to WordPress’s REST API (or GraphQL) endpoint, and it is up to the frontend to assemble and serve the generated HTML. 

For a Headless site, a request would look more like this:

  • A user requests a page on your website.
  • The front-end application (e.g., Next.js, Astro, or another framework) may relay this request to WordPress via the REST API or the GraphQL endpoint. This may be unnecessary because the HTML could already be generated if we’re doing a fully static build or if the response is already cached.
  • The request would go to WordPress, which is similar to a more traditional setup.
  • WordPress will invoke the REST API Router (for REST), or WPGraphQL will parse the query.
  • The database is queried.
  • JSON is generated and returned to the front-end application, which handles the JSON return data (e.g., updating the local state, re-rendering the DOM, etc.).

Headless refers to any WordPress build in which WordPress acts as the content layer while the frontend is served separately. There are many ways of doing this, and it will work differently across different applications.

Some frontend applications will use server-side rendering (SSR), where the markup is generated via a node server (and cached). Many frameworks have “adapters” for this, such as Astro’s Cloudflare adapter, which abstracts the SSR logic away from you.

Some Headless sites are fully static, leveraging static site generation (SSG), where the WordPress backend is only used to generate the site’s HTML files. Once the site is built, the WordPress API is no longer needed until the next update (like when you publish a new blog post or edit an existing page) triggers a rebuild. That means every time you change your website or content, the site will have to be rebuilt (either entirely or partially via “partial SSG”).

When the site is live, all the HTML/markup is already built, and users are being served those static HTML files.

The build method you choose depends on the project and what is most efficient for your use case. For example, can you pre-render this page ahead of a user’s request? If so, SSG is likely the best fit.

This is also a good time to research the host where you plan to host your front-end application, review their documentation, and see what adapters or workflows exist.

For example, WordPress.com provides a managed, scalable, and secure WordPress environment for sites of any size. This eliminates many of the infrastructure headaches associated with a self-hosted WordPress setup. You have all the features needed for custom WordPress builds, knowing everything is handled.

Using the Business plan, you have a perfect starting point for your Headless build with full access to developer features like GitHub deployments, real-time backups, and SSH.

Using GraphQL or the WordPress core REST API?

WordPress includes a built-in REST API, which is widely supported by third-party and community plugins. The API is also used in WordPress core code and in Gutenberg.

The REST API allows users (logged in and logged out) to perform common CRUD operations on posts, pages, media, and other entities, depending on their access level.

In your front-end code base, you can opt to use the REST API, or if you prefer, you can use the WPGraphQL plugin, which allows you to perform the same operations via GraphQL queries.

Many developers building Headless WordPress sites use GraphQL alongside modern frameworks like Astro, Next.js, or Nuxt.

With GraphQL, we can request only the fields we need and retrieve related data via nested queries. For example, we can use one query to fetch a post and its author with the name and avatar image URL:

A query to fetch a post, its author with the name and avatar image URL

A similar call to /wp-json/wp/v2/posts?slug=hello-world will give us many more fields. As you can see below, while the REST API does give us the author ID, we cannot get the avatar URL by default from the same request.

A call to the WordPress REST API in a terminal showing the output that excludes author avatar URL

On the other hand, the WordPress REST API is supported out of the box, with no configuration needed. This has led to a larger ecosystem where plugins provide their endpoints via the WordPress REST API (one example is WooCommerce).

I encourage you to check out both and see which will work better for your project.

Who thrives with Headless WordPress?

Headless WordPress is often adopted by agencies and developers who want complete control over a site’s frontend. It uses the time-tested and securely managed backend of a managed WordPress host like WordPress.com

Some other use cases include:

  • Enterprises and high-traffic websites: Headless WordPress is best for organizations that need a scalable content management system without the hassle of server management.
  • Media and content-heavy platforms: Publishers who need fast, API-driven content delivery across multiple channels may opt for a Headless WordPress setup.
  • Ecommerce and SaaS applications: Businesses integrating WordPress content with custom storefronts, web apps, or mobile apps may find a Headless setup more suited to their needs.

You can gradually adopt a Headless setup or integrate it into your WordPress site by interacting with the WordPress REST API from within your theme.

Are there any drawbacks to choosing a Headless setup?

After reading the above, it may seem that Headless WordPress is always the best option. However, like anything else, a Headless WordPress setup has benefits and drawbacks. 

For many projects, especially if you’re not a developer, relying on WordPress for the whole stack makes more sense. With this more traditional WordPress setup, you still have a lot of ways of adding interactivity via the block editor and the Interactivity API. Plus, everything just works using a traditional WordPress setup because the software is so powerful as-is.

A Headless setup comes with some potential drawbacks, including:

  • More maintenance work: Two separate codebases and technologies powering the front-end and back-end create complexities that you don’t have to deal with when using a traditional WordPress setup.
  • The wide selection of themes, patterns, and design functionality WordPress is known for will be largely unavailable: You will be responsible for implementing much of this from scratch with code. How will you handle blog comments? How about contact forms? This functionality is built into the WordPress software to make it easier for end-users to implement.
  • Not all plugins support Headless setups: You may have to extend plugins or manually expose plugin data to the REST API or GraphQL. 
  • Managing two hosting environments: You’ll need one environment for the WordPress backend and one for the frontend. For many sites, the frontend can be hosted as static files on the edge using technologies like GitHub, AWS Cloudfront, Cloudflare, or several other static file hosts.

Things to keep in mind before opting for a Headless site

Still not sure if a Headless WordPress setup is right for you? Consider the following:

  • Custom code and experiences: A Headless build requires developer time and technical decisions tailored to your project. You should ask yourself if the flexibility of Headless architecture is really necessary for your project.
  • Technology familiarity: Are you or your team more used to working with PHP or JavaScript?
  • Your project’s goals: While Headless sites offer more flexibility and may increase performance (plus they’re unique, challenging, and fun sites for developers to build), these projects often require increased complexity and more time spent on development.
  • WordPress’ under-the-hood tech: Without WordPress’ built-in caching and optimization features, you’ll need to implement these yourself using a caching layer or service.
  • Cache strategies: With an optimized caching strategy that integrates CDN edge servers with server-side caching—such as Varnish, NGINX FastCGI cache, or a WordPress caching plugin—a WordPress site may achieve performance levels comparable to a static site.
  • WordPress is SEO-friendly out of the box: With a Headless strategy, you must ensure that the front-end handles SEO properly. This would involve SSR or SSG, which is already supported in common front-end frameworks. You would also need to fetch SEO data from WordPress (such as whether a page should be indexed, its SEO title, and its metadata). Redirects must also be appropriately handled, as you’ll lose the built-in WordPress permalink handling with a Headless setup.
  • RSS feeds and sitemaps: With a Headless setup, this functionality may need to be coded and served from the frontend; it is already provided in WordPress core (and Jetpack if you’re hosting on WordPress.com).

Your Headless WordPress roadmap: Getting started

So Headless WordPress is right for your project? Here’s a quick getting started guide to help you out.

Preparing the backend: Plugins and site setup

The first thing you need is a WordPress site.

Tip: WordPress.com’s Business plan or above provides a managed, scalable, and secure WordPress environment for sites of any size.

WordPress.com eliminates many of the infrastructure headaches associated with a self-hosted setup. You have all the features needed for custom WordPress builds, knowing everything behind the scenes is handled. Using WordPress.com, you have a perfect starting point for your Headless build with full access to developer features like GitHub deployments, real-time backups, and SSH.

If you want to just test a few things and follow along with this tutorial, you can also use WordPress.com’s free and open source local development environment, Studio, to spin up a local WordPress installation.

WordPress ships with a REST API, but as mentioned above, many developers opt for the WPGraphQL plugin when building Headless sites, which allows us to add a GraphQL endpoint to your WordPress site. 

If you opt to use the REST API instead, you can start without installing any plugins.

Creating a content structure for API consumption

Let’s consider a WordPress post or page. We have a title, an ID, a slug, a featured image, and a few more fields. However, most posts have rich content added via the editor, which makes up most of the post content.

For this reason, the post content from the block editor may vary significantly between posts.

On the other hand, content like WooCommerce products or a custom post type with custom fields (for example, a post type defined with Secure Custom Fields) may have many more meta fields and little or no content from the block editor.

Why does this matter? The structured meta fields, such as the post title, are easier to handle when pulling content from WordPress. We have a pretty good idea of how it will look and what data we’ll find there.

The block editor content, on the other hand, is a large string of text containing blocks and nested blocks. We have less control over this content and can make fewer assumptions about its shape.

The simple way to handle block content is to set it directly as HTML in a div on the frontend. This will give you the same CSS classes and markup as the WordPress post, and you can style these in your front-end app or import the block styles as part of your build process.

Another approach is to fetch the Gutenberg block markup, recursively parse the content, and map the blocks to corresponding components on your frontend. For example, a Gutenberg block, like an image, can be parsed to an equivalent .tsx or .astro component in your front-end code.

While it gives you more flexibility, it also means you must write a new component for every block you plan to use.

This is also where you should consider what data you need from WordPress. Some use cases may only require fetching posts, while others need menus, SEO data, and user information. 

Contact forms or comment submissions may also need to be returned to WordPress via REST requests unless you plan to handle them differently.

Fetching data

On your WordPress site’s dashboard, head to the WPGraphQL area. You’ll see the GraphQL IDE, which is where you can start interfacing with WordPress via GraphQL. 

Tip: If you’re unfamiliar with GraphQL, check out the WPGraphQL docs.

It’s easy to build complex queries with clauses, pagination handling, and nested data while seeing the output instantly in the admin using the IDE.

Output in the WPGraphQL IDE on the right and the call on the left

Building the frontend

Once we can fetch data from the backend, either via REST or GraphQL, we can start translating this logic to our frontend.

Astro is a good option, and I added some notes on the integration below. 

Due to the variety of sites, use cases, and frameworks, this is by no means a complete tutorial on how to build a WordPress-powered Astro site. Still, the steps are general enough that they will apply to most similar frontend frameworks and give you an idea of how to get started.

You can start a new Astro project by running the following in your terminal:

npm create astro@latest -- --template blog

This will give you the latest version of Astro with prebuilt blog templates. By default, this blog is powered by Astro’s content collections and will render markdown (and MDX) from .md and .mdx files stored in the frontend repository.

the output of create-astro --template blog in a terminal

In addition, we’ll need a few dependencies for interfacing with WordPress via GraphQL:

npm install graphql-request graphql

Let’s start our project to see what we’re working with by running npm run dev. From the terminal output, we can see that the site runs on localhost:4321.

The default Astro blog template

Our current Astro site renders content from files in the src/pages directory, where the [...slug].astro is dynamic and responsible for parsing and rendering the markdown files inside the src/content/blog directory. 

Astro directory tree

Since we’ll get our content from WordPress, we can remove the src/content directory and the content.config.ts file.

In src/consts.ts, define a new constant for your site’s WPGraphQL endpoint. Reminder: This can be a live site or a local Studio site.

// Place any global data in this file.
// You can import this data from anywhere in your site by using the `import` keyword.

export const SITE_TITLE = 'Astro Blog';
export const SITE_DESCRIPTION = 'Welcome to my website!';
export  const WORDPRESS_API_URL = 'https://astroheadlessbuild.wpcomstaging.com/graphql';
Astro blog global data in a code editor with a dark theme

We already know we need to get all posts, the slugs, and a single post given a slug. As we progress, more queries will likely be required. Category, tag, and author pages already come to mind. 

We can create a new file at src/lib/graphql.ts

Any query you need can be added and exported from this file. The IDE inside the WPGraphQL admin page is a great place to experiment and write new queries. Let’s add one to fetch all our posts for now:

import { GraphQLClient } from 'graphql-request';
import { WORDPRESS_API_URL } from '../consts';

// Create a GraphQL client instance
export const graphQLClient = new GraphQLClient(WORDPRESS_API_URL);

// Query to get a list of posts
export const GET_POSTS = `
  query GetPosts($first: Int, $after: String) {
    posts(first: $first, after: $after) {
      pageInfo {
        hasNextPage
        endCursor
      }
      nodes {
        id
        slug
        title
        date
        excerpt
        featuredImage {
          node {
            sourceUrl
            altText
          }
        }
      }
    }
  }
`;

Using the fetched data in our frontend

In Astro, we’re opting for a static build. Because of this, we must tell it which pages to build for us. 

We can modify the [...slug].astro file with getStaticPaths, allowing Astro to know all the possible URLs/paths at build time.

It also allows us to use the data directly in the template:

import { graphQLClient, GET_POSTS } from '../../lib/graphql';
import type { WordPressPostsResponse, WordPressTerm } from '../../lib/types';
import BlogPost from '../../layouts/BlogPost.astro';
import { formatDate } from '../../lib/utils';

export async function getStaticPaths() {
  const allPaths = [];
  let afterCursor = null;
  let hasNextPage = true;

  while (hasNextPage) {
    const response: WordPressPostsResponse = await graphQLClient.request(GET_POSTS, {
      first: 10, // Fetch in batches of 10
      after: afterCursor,
    });

    allPaths.push(
      ...response.posts.nodes.map(post => ({
        params: { slug: post.slug },
        props: { post },
      }))
    );

    hasNextPage = response.posts.pageInfo.hasNextPage;
    afterCursor = response.posts.pageInfo.endCursor;
  }

  return allPaths; // Return an array as required by Astro
}

const { post } = Astro.props;

if (!post) {
	return Astro.redirect('/404');
}

// Format the post data to match the BlogPost component props
const postData = {
	title: post.title,
	description: post.excerpt.replace(/<[^>]*>/g, ''), // Strip HTML tags
	pubDate: formatDate(post.date),
	updatedDate: formatDate(post.date),
	heroImage: post.featuredImage?.node.sourceUrl || undefined,
};

// Get the post content
const content = post.content || '';

// Get additional post metadata
const author = post.author?.node;
const categories = post.categories?.nodes || [];
const tags = post.tags?.nodes || [];

We can now run npm run build && npm run preview, which will convert all our static paths (e.g., blog posts) into HTML files and serve the static files from a local dev server:

An Astro blog with a post called 'Hello World!' with a featured image of a tabby cat
The generating static routes output from Astro

Final thoughts: Going Headless with WordPress

In this post, we’ve covered the pros and cons of Headless WordPress, how to fetch data from our WordPress.com backend, and how you can quickly get started with a new Headless frontend in Astro.

Although my example is a very simple site, WordPress.com offers a robust, low-maintenance backend for Headless sites of any size, whether it is an ecommerce site, an app, or a content-heavy site. 

Our managed infrastructure, security, and API-first capabilities make WordPress.com an excellent choice for businesses and developers looking to scale.