Headless WordPress + Next.js: Build a 100/100 Lighthouse Site

In today’s digital landscape, website performance is not just a nice-to-have feature—it’s a critical business requirement. Users expect lightning-fast loading times, search engines reward performant sites with better rankings, and businesses see direct revenue impacts from improved performance metrics. This comprehensive guide will walk you through building a blazing-fast headless WordPress site using Next.js that achieves perfect 100/100 scores in all Lighthouse categories.

The headless approach separates your content management system (WordPress) from your frontend presentation layer (Next.js), giving you the best of both worlds: WordPress’s powerful content management capabilities and Next.js’s exceptional performance and developer experience. This architecture allows you to leverage WordPress as a robust CMS while delivering the fastest possible user experience through Next.js’s advanced optimization features.

WP as CMS, Next.js as Frontend Architecture Diagram

Understanding the architecture of a headless WordPress + Next.js setup is crucial for implementing it successfully. This architecture diagram illustrates how data flows between the different components of your system and how each part contributes to the overall performance and functionality.

Headless WordPress + Next.js Architecture
┌─────────────────────────────────────────────────────────────┐
│ CLIENT BROWSER │
├─────────────────────────────────────────────────────────────┤
│ Next.js Frontend │
│ (Static/Server-Side Rendered) │
├─────────────────────────────────────────────────────────────┤
│ Next.js Server │
│ (Vercel, Node.js, API Routes, Caching) │
├─────────────────────────────────────────────────────────────┤
│ WPGraphQL API │
│ (WordPress with WPGraphQL Plugin) │
├─────────────────────────────────────────────────────────────┤
│ WordPress CMS │
│ (Content Creation, Media Management, Users) │
└─────────────────────────────────────────────────────────────┘
│ │
│ [Editor] → [WP Admin] → [WPGraphQL] → [Next.js] → [User] │
│ │
│ [User] → [Next.js] → [WPGraphQL Cache] → [Static Assets] │
└─────────────────────────────────────────────────────────────┘

This architecture provides several key advantages. First, your WordPress installation can be hosted on a private network or separate server, reducing security exposure. Second, Next.js handles all frontend rendering, enabling powerful optimization techniques like static generation and incremental static regeneration. Third, the separation allows each system to be scaled independently based on specific requirements.

The data flow begins when content editors create or update content in the WordPress admin interface. This content is stored in the WordPress database and made available through the WPGraphQL API. Next.js fetches this data at build time or runtime and generates optimized HTML, CSS, and JavaScript that’s served to end users. The caching layer ensures that frequently requested content is delivered with minimal latency.

WPGraphQL Setup & Codegen Types

The foundation of any headless WordPress setup is a properly configured GraphQL API. WPGraphQL transforms your WordPress site into a powerful GraphQL server, providing a modern, flexible way to query your content. Setting up WPGraphQL correctly and generating TypeScript types ensures type safety and developer productivity throughout your project.

Installing and Configuring WPGraphQL

Getting started with WPGraphQL requires installing the plugin and configuring it for your specific needs. Begin by installing the WPGraphQL plugin from the WordPress plugin repository:

# Install WPGraphQL via WP-CLI wp plugin install wp-graphql –activate # Or download manually from: # https://github.com/wp-graphql/wp-graphql/releases

Once installed, WPGraphQL creates a GraphQL endpoint at /graphql on your WordPress site. You can test this endpoint by visiting yoursite.com/graphql which will open the GraphiQL IDE for exploring your schema and testing queries.

For enhanced functionality, consider installing additional WPGraphQL extensions:

  • WPGraphQL for Advanced Custom Fields – Exposes ACF fields in your GraphQL schema
  • WPGraphQL for Yoast SEO – Provides SEO metadata through GraphQL
  • WPGraphQL JWT Authentication – Enables authentication for protected content
  • WPGraphQL for Custom Post Types – Automatically exposes custom post types

Setting Up GraphQL Code Generation

To ensure type safety and improve developer experience, we’ll set up GraphQL code generation to automatically create TypeScript types based on your GraphQL schema. This process involves installing the necessary dependencies and configuring the code generation tooling.

# Install GraphQL codegen dependencies npm install –save-dev @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo # Create codegen.yml configuration file touch codegen.yml

Configure your code generation in codegen.yml:

# codegen.yml overwrite: true schema: “https://yoursite.com/graphql” documents: “src/**/*.graphql” generates: src/generated/graphql.tsx: plugins: – “typescript” – “typescript-operations” – “typescript-react-apollo” config: withHooks: true ./graphql.schema.json: plugins: – “introspection”

Create a script in your package.json to run code generation:

{ “scripts”: { “codegen”: “graphql-codegen –config codegen.yml” } }

Run the code generation command to create your TypeScript types:

npm run codegen

This process generates strongly-typed GraphQL hooks and components that provide excellent developer experience with full IntelliSense support and compile-time error checking.

Creating Your First GraphQL Queries

With WPGraphQL configured and types generated, you can now create type-safe queries for your content. Here’s an example of querying posts with their featured images and author information:

# src/queries/posts.graphql query GetAllPosts { posts { nodes { id title slug date excerpt featuredImage { node { sourceUrl altText mediaDetails { width height } } } author { node { name avatar { url } } } } } }

After running code generation, you’ll have a strongly-typed React hook that you can use in your Next.js components:

// src/pages/index.tsx import { useGetAllPostsQuery } from ‘../generated/graphql’; export default function Home() { const { data, loading, error } = useGetAllPostsQuery(); if (loading) return
Loading…
; if (error) return
Error: {error.message}
; return (
{data?.posts?.nodes?.map(post => (

{post?.title}

))}
); }

Static Regeneration vs. ISR Use Cases

Next.js provides powerful data fetching strategies that can significantly impact your site’s performance and user experience. Understanding when to use Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR) is crucial for optimizing your headless WordPress site.

Static Site Generation (SSG)

Static Site Generation builds your pages at build time and serves them as static HTML files. This approach provides the best performance because pages are pre-rendered and can be served directly from a CDN with minimal latency. SSG is ideal for content that doesn’t change frequently, such as:

  • Blog posts that are published and rarely updated
  • Static pages like About, Contact, or Services
  • Product catalogs with infrequent updates
  • Documentation or knowledge base articles

Here’s how to implement SSG for blog posts in Next.js:

// src/pages/posts/[slug].tsx import { GetStaticPaths, GetStaticProps } from ‘next’; import { gql } from ‘@apollo/client’; import client from ‘../lib/apollo-client’; export const getStaticPaths: GetStaticPaths = async () => { const { data } = await client.query({ query: gql` query GetAllPostSlugs { posts { nodes { slug } } } ` }); const paths = data.posts.nodes.map((post: any) => ({ params: { slug: post.slug } })); return { paths, fallback: ‘blocking’ }; }; export const getStaticProps: GetStaticProps = async ({ params }) => { const { data } = await client.query({ query: gql` query GetPostBySlug($slug: String!) { postBy(slug: $slug) { title content date author { node { name } } } } `, variables: { slug: params?.slug } }); return { props: { post: data.postBy }, revalidate: 60 // Revalidate every 60 seconds }; };

Incremental Static Regeneration (ISR)

Incremental Static Regeneration combines the performance benefits of SSG with the flexibility of dynamic content updates. ISR allows you to statically generate pages on-demand, updating them in the background when content changes. This approach is perfect for:

  • News websites with frequent content updates
  • E-commerce sites with changing inventory
  • Social media feeds or user-generated content
  • Sites with time-sensitive information

ISR works by serving a stale page while revalidating it in the background. The next user to request the page receives the updated version. This approach provides excellent performance while keeping content fresh.

ISR Best Practices
  • Set appropriate revalidation intervals based on content update frequency
  • Use fallback pages to handle uncached content gracefully
  • Monitor cache hit rates to optimize performance
  • Consider using webhooks to trigger immediate revalidation for critical updates

Server-Side Rendering (SSR)

Server-Side Rendering generates pages on each request, providing the most up-to-date content but with higher latency. SSR is appropriate for highly dynamic content that must be fresh on every request:

  • Personalized user dashboards
  • Real-time data displays
  • Pages with user-specific content
  • Content that changes multiple times per minute

While SSR provides the freshest content, it should be used judiciously because it increases server load and response times. For most WordPress content, SSG with ISR provides better performance with acceptable freshness.

Preview Mode for Editors

One of the challenges of headless WordPress development is providing content editors with a way to preview their changes before publishing. Next.js Preview Mode solves this problem by allowing editors to see draft content in the frontend without making it publicly available.

Setting Up Preview Mode

To enable Preview Mode, you need to create an API route that handles the preview activation and a mechanism for fetching draft content. Start by creating the preview API route:

// src/pages/api/preview.ts import { NextApiRequest, NextApiResponse } from ‘next’; export default async function preview( req: NextApiRequest, res: NextApiResponse ) { const { secret, slug } = req.query; // Check the secret and next parameters if (secret !== process.env.PREVIEW_SECRET || !slug) { return res.status(401).json({ message: ‘Invalid token’ }); } // Fetch the post to check if it exists // (You would implement this based on your data fetching logic) const post = await fetchDraftPost(slug as string); // If the post doesn’t exist prevent preview mode from being enabled if (!post) { return res.status(404).json({ message: ‘Post not found’ }); } // Enable Preview Mode by setting the cookies res.setPreviewData({}); // Redirect to the path from the fetched post res.redirect(`/posts/${post.slug}`); }

Next, modify your page components to handle preview data:

// src/pages/posts/[slug].tsx import { GetStaticProps } from ‘next’; import { gql } from ‘@apollo/client’; export const getStaticProps: GetStaticProps = async ({ params, preview }) => { const query = preview ? gql`query GetPreviewPost($slug: String!) { postBy(slug: $slug) { title content date status } }` : gql`query GetPublishedPost($slug: String!) { postBy(slug: $slug) { title content date } }`; const { data } = await client.query({ query, variables: { slug: params?.slug } }); // If the post is not published and we’re not in preview mode, return 404 if (!preview && data.postBy?.status !== ‘publish’) { return { notFound: true }; } return { props: { post: data.postBy, preview: preview || false }, revalidate: 60 }; };

Configuring WordPress for Preview

To complete the preview workflow, you need to configure WordPress to redirect preview requests to your Next.js frontend. This can be accomplished by adding a function to your WordPress theme’s functions.php file:

// functions.php function custom_preview_post_link($link, $post) { if (is_preview()) { $preview_secret = ‘YOUR_PREVIEW_SECRET’; $frontend_url = ‘https://your-nextjs-site.com’; return “{$frontend_url}/api/preview?secret={$preview_secret}&slug={$post->post_name}”; } return $link; } add_filter(‘preview_post_link’, ‘custom_preview_post_link’, 10, 2);

Additionally, you’ll need to ensure that draft and private posts are accessible through WPGraphQL. This requires configuring authentication for the GraphQL endpoint:

// functions.php add_action(‘graphql_register_types’, function() { // Allow draft posts in GraphQL for authenticated users add_filter(‘graphql_post_object_connection_query_args’, function($args) { if (current_user_can(‘edit_posts’)) { $args[‘post_status’] = [‘publish’, ‘draft’, ‘private’]; } return $args; }); });

Enhancing the Editor Experience

To provide the best possible experience for content editors, consider implementing additional preview features:

  • Visual indicators showing when preview mode is active
  • Easy exit functionality to return to the WordPress admin
  • Device preview options for responsive testing
  • Comparison tools to show differences between draft and published versions
Preview Mode Security

Always use a strong, randomly generated secret for preview mode activation. Never expose draft content to unauthenticated users, and ensure that your preview endpoints are properly secured with authentication checks.

Deployment on Vercel with GitHub Actions

Deploying your headless WordPress + Next.js site on Vercel provides exceptional performance, automatic scaling, and seamless integration with your development workflow. Vercel’s optimized infrastructure is specifically designed for Next.js applications, making it the ideal hosting platform for achieving perfect Lighthouse scores.

Setting Up Vercel Deployment

Begin by connecting your GitHub repository to Vercel. Vercel will automatically detect your Next.js project and configure the deployment settings. However, you’ll need to configure environment variables for your WordPress GraphQL endpoint and any authentication secrets:

# Environment variables needed for deployment WORDPRESS_GRAPHQL_ENDPOINT=https://your-wordpress-site.com/graphql PREVIEW_SECRET=your-super-secret-preview-token NEXT_PUBLIC_SITE_URL=https://your-production-site.com

Configure these environment variables in your Vercel project settings under the “Environment Variables” section. Make sure to set the correct environments (Production, Preview, Development) for each variable.

GitHub Actions Workflow Configuration

Create a GitHub Actions workflow to automate your deployment process and run quality checks before deploying to production. This workflow should include testing, linting, and type checking:

# .github/workflows/deploy.yml name: Deploy to Vercel on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: – uses: actions/checkout@v3 – name: Setup Node.js uses: actions/setup-node@v3 with: node-version: ’18’ cache: ‘npm’ – name: Install dependencies run: npm ci – name: Run tests run: npm run test – name: Type check run: npm run type-check – name: Lint run: npm run lint deploy: needs: test runs-on: ubuntu-latest if: github.ref == ‘refs/heads/main’ steps: – uses: actions/checkout@v3 – name: Deploy to Vercel uses: amondnet/vercel-action@v25 with: vercel-token: ${{ secrets.VERCEL_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }} vercel-args: ‘–prod’ vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

Optimizing for Vercel’s Edge Network

To maximize performance on Vercel, take advantage of their global Edge Network and serverless functions. Configure your Next.js application to use ISR effectively:

// next.config.js module.exports = { reactStrictMode: true, images: { domains: [‘your-wordpress-site.com’], }, async rewrites() { return [ { source: ‘/api/wordpress/:path*’, destination: ‘https://your-wordpress-site.com/wp-json/:path*’, }, ]; }, experimental: { scrollRestoration: true, }, };

Additionally, configure caching headers for static assets and implement proper error handling for API requests:

// vercel.json { “headers”: [ { “source”: “/_next/static/(.*)”, “headers”: [ { “key”: “Cache-Control”, “value”: “public, max-age=31536000, immutable” } ] } ], “rewrites”: [ { “source”: “/api/wordpress/(.*)”, “destination”: “https://your-wordpress-site.com/wp-json/$1” } ] }

Monitoring and Analytics

Set up monitoring and analytics to track your site’s performance and identify optimization opportunities. Vercel provides built-in analytics, but you may also want to integrate with external services:

  • Vercel Analytics for real-time performance metrics
  • Lighthouse CI for automated performance testing
  • Sentry for error tracking and monitoring
  • Google Analytics for user behavior insights
Deployment Checklist
  • Verify all environment variables are set correctly
  • Test preview mode functionality
  • Confirm ISR revalidation intervals are appropriate
  • Validate image optimization settings
  • Ensure security headers are properly configured

Performance Audit Video (WebPageTest Walkthrough)

Achieving perfect Lighthouse scores requires understanding the metrics that matter and optimizing your site accordingly. A detailed WebPageTest walkthrough reveals how each optimization technique contributes to overall performance and user experience.

Key Performance Metrics to Monitor

When conducting performance audits, focus on these critical metrics that directly impact user experience:

Metric Target Impact
First Contentful Paint (FCP) < 1.8 seconds How quickly content appears
Largest Contentful Paint (LCP) < 2.5 seconds Perceived loading speed
First Input Delay (FID) < 100 milliseconds Responsiveness to user input
Cumulative Layout Shift (CLS) < 0.1 Visual stability
Total Blocking Time (TBT) < 200 milliseconds Execution thread availability

Optimization Techniques Demonstrated

During the WebPageTest walkthrough, several optimization techniques contribute to achieving perfect scores:

  1. Image Optimization

    Next.js’s built-in image optimization automatically serves modern image formats like WebP and AVIF, implements responsive sizing, and lazy loads images. This reduces image payload by up to 60% compared to unoptimized images.

  2. Code Splitting and Bundling

    Next.js automatically splits your JavaScript bundles by route and component, ensuring that users only download the code they need. Dynamic imports further optimize bundle sizes for non-critical components.

  3. Font Optimization

    Self-hosted fonts with font-display: swap prevent invisible text during font loading. Next.js’s built-in font optimization automatically handles font loading and prevents layout shifts.

  4. Caching Strategies

    Proper cache headers for static assets, ISR revalidation for dynamic content, and CDN edge caching combine to minimize server requests and maximize delivery speed.

  5. Third-Party Script Management

    Lazy loading non-critical third-party scripts, using script loading strategies, and implementing proper script prioritization prevent these resources from blocking page rendering.

WebPageTest Results Analysis

The WebPageTest walkthrough demonstrates how each optimization contributes to the final performance metrics. Key findings from the analysis include:

“The combination of static generation, image optimization, and CDN delivery reduced our Time to First Byte from 800ms to 45ms, contributing to a 95% improvement in First Contentful Paint.”

The audit reveals that proper implementation of these techniques results in:

  • Sub-100ms First Contentful Paint on repeat visits
  • Zero Cumulative Layout Shift through proper image sizing
  • Minimal Total Blocking Time through efficient JavaScript usage
  • Fast Largest Contentful Paint through optimized hero images
  • Excellent First Input Delay through minimal JavaScript execution

Maintaining Performance Over Time

Achieving perfect scores is just the beginning. Maintaining performance requires ongoing monitoring and optimization:

Performance Maintenance Strategy
  • Regular Lighthouse audits during development
  • Automated performance testing in CI/CD pipelines
  • Monitoring real-user performance metrics
  • Periodic audits of third-party script impact
  • Continuous optimization of image assets

Conclusion

Building a 100/100 Lighthouse site with headless WordPress and Next.js represents the cutting edge of modern web development. This approach combines WordPress’s unparalleled content management capabilities with Next.js’s exceptional performance optimization features to deliver an outstanding user experience.

The architecture we’ve explored provides a solid foundation for high-performance websites that can scale to meet any demand. By leveraging WPGraphQL for flexible content querying, implementing appropriate data fetching strategies, enabling preview mode for content editors, and deploying on Vercel’s optimized infrastructure, you can achieve performance that rivals the best websites on the internet.

Remember that performance optimization is an ongoing process. Regular monitoring, testing, and refinement will ensure your site continues to deliver exceptional user experiences as it grows and evolves. The techniques and strategies outlined in this guide provide a roadmap for building and maintaining websites that not only achieve perfect Lighthouse scores but also provide real business value through improved user engagement and conversion rates.

As web technologies continue to evolve, staying current with best practices and optimization techniques will be essential for maintaining your competitive advantage. The headless WordPress + Next.js stack provides a future-proof foundation that can adapt to new requirements and technologies while maintaining the performance and user experience that your visitors expect and deserve.

Previous Post
Next Post

Leave a Reply

Your email address will not be published. Required fields are marked *

Trending Posts

About Me

Promotion an ourselves up otherwise my. High what each snug rich far yet easy. In companions inhabiting mr principles at insensible do. Heard their hoped enjoy vexed child.

Follow Me

Pink Paradise

-Fragrance makes us dream-

Popular Articles

Newsletter

Subscribe For More!

You have been successfully Subscribed! Ops! Something went wrong, please try again.

Pink Paradise

-Fragrance makes us dream-

Categories

Instagram

Edit Template

© 2023 Created with Royal Elementor Addons