Headless deployment overview

In a headless architecture, the Next.js frontend and the WordPress backend are hosted separately. The frontend is deployed on a platform optimized for JavaScript applications (Vercel, Netlify, AWS Amplify), while WordPress stays on a classic or managed PHP host.

Why Vercel for a Next.js frontend

Vercel is the platform created by the team that develops Next.js. It offers native integration with all the framework's features.

~50

edge regions

Global distribution network for minimal response times

<1s

from deploy to deploy

Each Git push triggers an automatic build and deployment

100%

Next.js compatibility

ISR, Server Components, Middleware and Image Optimization out of the box

Connecting the Git repository

Create a Vercel account

Go to vercel.com and sign in with your GitHub, GitLab or Bitbucket account. The free Hobby plan is enough for a personal project or a prototype.

Import the Git repository

Click "New Project" and select the repository containing your Next.js application. Vercel automatically detects the framework and configures the build settings.

Configure environment variables

Add the necessary environment variables in the Vercel project settings: WORDPRESS_API_URL, WORDPRESS_AUTH_TOKEN, REVALIDATION_SECRET. These values are encrypted and only accessible at build time and during serverless execution.

Trigger the first deployment

Click "Deploy". Vercel runs npm install, then next build, and finally deploys the result to its edge network. The production URL is available immediately.

Environment variables

Environment variables are configured in the Vercel dashboard (Settings > Environment Variables). They can be set per environment: Production, Preview and Development.

# Variables required for a headless frontend
WORDPRESS_API_URL=https://admin.your-site.com/wp-json
WORDPRESS_AUTH_TOKEN=secret_token_for_protected_endpoints
REVALIDATION_SECRET=shared_secret_for_isr_webhooks

# Optional variables
NEXT_PUBLIC_SITE_URL=https://www.your-site.com
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX

Difference between server and client variables

Variables prefixed with NEXT_PUBLIC_ are included in the JavaScript bundle sent to the browser. Never store secrets (tokens, private API keys) in NEXT_PUBLIC_ variables. Variables without that prefix are only accessible on the server (Server Components, Route Handlers, serverless functions).

Build settings

Vercel automatically detects a Next.js project and applies the following settings:

| Setting | Default value | Customization | |---|---|---| | Framework Preset | Next.js | Automatic | | Build Command | next build | Customizable (npm run build) | | Output Directory | .next | Automatic | | Install Command | npm install | Customizable (pnpm install, yarn) | | Node.js Version | 18.x | Configurable (18.x, 20.x) |

Preview Deployments

Each pull request or push to a non-production branch automatically generates a "Preview Deployment" with a unique URL. This feature lets you visually verify changes before merging them.

# Example preview URL
https://your-project-git-branch-name-your-team.vercel.app

Preview deployments use the environment variables of the "Preview" environment, which lets you point to a WordPress staging server if needed.

Custom domain

Configuring a custom domain happens in Settings > Domains:

  1. Add your domain (for example www.your-site.com)
  2. Configure the DNS records at your registrar:
    • CNAME: www to cname.vercel-dns.com
    • A: @ to 76.76.21.21 (for the apex domain without www)
  3. Vercel automatically generates and renews the SSL certificate

Domain separation

Use distinct domains or subdomains for the frontend and the backend. For example: www.your-site.com for the Next.js frontend and admin.your-site.com for the WordPress back-office. This separation clarifies the architecture and simplifies SSL certificate and DNS rule management.

WordPress hosting: the options

The WordPress backend requires PHP hosting with MySQL. Several options exist depending on performance and budget needs.

In headless mode, WordPress server performance has less impact on the user experience because pages are pre-generated (SSG) or cached (ISR). The WordPress server is mostly hit during the build and during revalidations.

CI/CD pipeline: automatic deployment

The CI/CD pipeline with Vercel runs automatically:

  1. Push to main: triggers a production deployment
  2. Push to a branch: triggers a preview deployment
  3. Pull request: creates a preview deployment and adds a comment with the URL

No additional CI/CD configuration is required. For advanced needs (pre-deployment tests, linting), add GitHub Actions on top.

# .github/workflows/ci.yml — tests before deployment
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run lint
      - run: npm run test

On-demand revalidation (On-Demand ISR)

ISR (Incremental Static Regeneration) lets you update static pages without redeploying the entire site. A WordPress webhook triggers revalidation whenever content is changed.

// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const body = await request.json();
  const secret = request.headers.get('x-revalidation-secret');

  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ message: 'Invalid secret' }, { status: 401 });
  }

  const { post_type, slug } = body;

  if (post_type === 'post') {
    revalidatePath(`/articles/${slug}`);
    revalidatePath('/articles');
  } else if (post_type === 'page') {
    revalidatePath(`/${slug}`);
  }

  revalidatePath('/'); // Revalidate the home page

  return NextResponse.json({ revalidated: true });
}

On the WordPress side, a hook sends the revalidation request when content is published or updated:

// functions.php — ISR revalidation webhook
add_action('save_post', function ($post_id) {
  if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;

  $post = get_post($post_id);
  if ($post->post_status !== 'publish') return;

  wp_remote_post('https://www.your-site.com/api/revalidate', [
    'headers' => [
      'Content-Type' => 'application/json',
      'x-revalidation-secret' => REVALIDATION_SECRET,
    ],
    'body' => json_encode([
      'post_type' => $post->post_type,
      'slug' => $post->post_name,
    ]),
  ]);
}, 10, 1);

Monitoring and analytics

Vercel provides built-in tracking tools:

  • Analytics: traffic, page views, unique visitors
  • Speed Insights: Core Web Vitals measured on field data (LCP, CLS, FID)
  • Logs: serverless function and build error logs
  • Usage: bandwidth consumption, serverless invocations, execution time

Alternative platforms

Costs in production

The Vercel free plan is suitable for a personal site or a prototype. In production with significant traffic, the Pro plan ($20/month per member) offers higher limits on bandwidth, serverless invocations and team members. Very high-traffic sites should evaluate the Enterprise plan with custom pricing.