LESSON 9 ⏱️ 12 min read

Deployment and Production

Preparing for Production

Before deploying, let's ensure everything is production-ready.

Environment Variables

Create .env.production:

NEXT_PUBLIC_WORDPRESS_URL=https://your-live-wordpress-site.com
NEXT_PUBLIC_SITE_URL=https://your-nextjs-domain.com
⚠️ Important: Never commit .env.local or sensitive credentials to git. Add them to .gitignore.

Build and Test Locally

Run a production build to catch issues:

npm run build

Check for errors or warnings. Common issues:

  • Missing environment variables
  • API connection errors
  • Image optimization warnings

Test the production build:

npm run start

Visit http://localhost:3000 and test all pages.

Deploying to Vercel

Vercel is the recommended platform for Next.js. Here's how to deploy:

1. Push to GitHub

git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/yourusername/your-repo.git
git push -u origin main

2. Connect to Vercel

  1. Go to vercel.com and sign in
  2. Click "New Project"
  3. Import your GitHub repository
  4. Configure the project:
- Framework Preset: Next.js

- Root Directory: ./ (or your project folder)

3. Set Environment Variables

In Vercel project settings → Environment Variables:

NEXT_PUBLIC_WORDPRESS_URL = https://your-wordpress-site.com

Click Deploy.

Configuring WordPress for Production

Enable CORS

Update your WordPress site to allow requests from Vercel:

// In theme's functions.php or a custom plugin
add_action('rest_api_init', function() {
    remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
    add_filter('rest_pre_serve_request', function($value) {
        $origin = get_http_origin();
        $allowed_origins = [
            'https://your-nextjs-domain.vercel.app',
            'https://your-custom-domain.com',
        ];
        
        if (in_array($origin, $allowed_origins)) {
            header('Access-Control-Allow-Origin: ' . $origin);
        }
        
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
        header('Access-Control-Allow-Headers: Content-Type, Authorization');
        return $value;
    });
}, 15);

Optimize REST API Performance

Add caching headers:

// Add cache headers to REST API responses
add_filter('rest_post_dispatch', function($response) {
    $response->header('Cache-Control', 'public, max-age=60, s-maxage=300');
    return $response;
});

On-Demand Revalidation

For instant updates when content changes, set up webhooks:

1. Create a Revalidation API Route

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

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidate-secret');
  
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
  }
  
  try {
    const body = await request.json();
    const { slug, type } = body;
    
    if (type === 'post' && slug) {
      // Revalidate specific post
      revalidatePath(`/blog/${slug}`);
      // Revalidate blog listing
      revalidatePath('/blog');
      // Revalidate homepage
      revalidatePath('/');
    }
    
    return NextResponse.json({ revalidated: true, now: Date.now() });
  } catch (error) {
    return NextResponse.json({ error: 'Error revalidating' }, { status: 500 });
  }
}

2. Add Environment Variable

In Vercel:

REVALIDATION_SECRET = your-secret-key-here

3. WordPress Webhook Plugin

Create a simple plugin or use WP Webhooks:

// In a custom plugin
add_action('save_post', function($post_id) {
    if (wp_is_post_revision($post_id)) return;
    
    $post = get_post($post_id);
    if ($post->post_status !== 'publish') return;
    
    $webhook_url = 'https://your-nextjs-domain.com/api/revalidate';
    
    wp_remote_post($webhook_url, [
        'headers' => [
            'Content-Type' => 'application/json',
            'x-revalidate-secret' => 'your-secret-key-here',
        ],
        'body' => json_encode([
            'type' => 'post',
            'slug' => $post->post_name,
        ]),
    ]);
});

Custom Domain

In Vercel:

  1. Go to Project Settings → Domains
  2. Add your custom domain
  3. Update DNS records as instructed
  4. Enable HTTPS (automatic)

Performance Monitoring

Enable Vercel Analytics

npm install @vercel/analytics
// src/app/layout.tsx
import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}

Speed Insights

npm install @vercel/speed-insights
import { SpeedInsights } from '@vercel/speed-insights/next';

// Add alongside Analytics
<SpeedInsights />

Deployment Checklist

Before going live:

  • [ ] All environment variables set
  • [ ] CORS configured on WordPress
  • [ ] Production build tested locally
  • [ ] Sitemap accessible at /sitemap.xml
  • [ ] Robots.txt configured
  • [ ] SSL certificate active
  • [ ] Webhook for revalidation working
  • [ ] Analytics tracking enabled
  • [ ] Error monitoring set up (Sentry, etc.)

Summary

In this lesson, we:

  • ✅ Prepared the project for production
  • ✅ Deployed to Vercel
  • ✅ Configured WordPress for production
  • ✅ Set up on-demand revalidation
  • ✅ Added analytics and monitoring

Congratulations! 🎉 You've built and deployed a complete headless WordPress site with Next.js!

Next Steps

  • Add a search feature
  • Implement comments
  • Add newsletter signup
  • Create custom post types
  • Add authentication for previews
🎉

Tutorial Complete!

You've finished all lessons in this series.

← Back to Tutorial Overview