Running WordPress purely as a content API — with a separate, faster frontend (React, Next.js, or a static site generator) consuming that data — combines WordPress's mature editing experience with modern frontend performance.
Why Go Headless with WordPress
- Keep WordPress's familiar content editing experience for non-technical editors
- Decouple frontend performance from WordPress/PHP rendering overhead
- Build the frontend in any modern framework, independent of WordPress themes
Step 1 — Install WordPress Normally
See Deploy WordPress with Docker Compose, or a traditional install — the backend setup is identical to standard WordPress.
Step 2 — Verify the REST API Is Accessible
curl https://cms.yourdomain.com/wp-json/wp/v2/posts
WordPress includes a REST API by default — no additional plugin required for basic content access.
Step 3 — Consider WPGraphQL for a GraphQL Alternative
Install the WPGraphQL plugin if you prefer GraphQL's flexible querying over the default REST API, particularly useful if your frontend needs varied data shapes across different pages.
Step 4 — Restrict the Traditional Frontend (Optional)
If WordPress's own theme/frontend rendering isn't needed at all, redirect frontend requests away from it, keeping only /wp-json/ and /wp-admin/ accessible:
location / {
return 301 https://yourfrontend.com$request_uri;
}
location /wp-json/ {
proxy_pass http://127.0.0.1:8080;
}
location /wp-admin/ {
proxy_pass http://127.0.0.1:8080;
}
Step 5 — Consume the API from Your Frontend
// Next.js example
async function getPosts() {
const res = await fetch('https://cms.yourdomain.com/wp-json/wp/v2/posts?_embed');
return res.json();
}
_embed includes related data (featured images, author info) in a single request, avoiding additional round-trips.
Step 6 — Handle Content Updates
Depending on your frontend architecture:
- Static site (built at deploy time) — trigger a rebuild via webhook when content is published; see How to Set Up a Jamstack Site with a Headless CMS Backend
- Server-rendered (Next.js SSR) — fetch fresh on each request, or use incremental static regeneration if your framework supports it
Setting Up a Publish Webhook
Use a WordPress plugin (or custom code hooking into publish_post) to send a webhook to your CI/CD pipeline whenever content is published or updated, triggering an automatic rebuild for static frontends.
Authentication for Preview/Draft Content
Use WordPress's application passwords feature (built into modern WordPress) to authenticate frontend requests needing access to draft/private content for preview purposes, rather than exposing admin credentials.
Securing the Headless WordPress Backend
- Restrict
/wp-admin/access to trusted IPs where feasible - Keep WordPress core, themes, and plugins updated (a smaller attack surface if theme/plugin usage is minimized in headless mode)
- Follow standard WordPress security practices — see the general WordPress backup and security guides
Common Errors
CORS errors when fetching from the frontend — configure appropriate CORS headers on the WordPress REST API responses, allowing requests specifically from your frontend's domain.
Missing featured images in API responses — ensure the _embed parameter is included in the API request, or fetch media data with a separate request.
Best Practices
- Minimize unnecessary theme/plugin usage since the traditional frontend isn't used
- Set up automatic rebuild triggers for static frontends when content changes
- Use application passwords rather than exposing admin credentials for preview functionality
Continue Reading
- Deploy WordPress with Docker Compose
- How to Set Up a Jamstack Site with a Headless CMS Backend
- How to Deploy a Next.js Application on a VPS
Browse more articles in Static Site Hosting & Frontend Deployment.
