- Deploy Next.js 16 to Netlify - SSR Guide for Builder.io
Deploy Next.js 16 to Netlify - SSR Guide for Builder.io
Use SSR and Netlify's plugin to fetch dynamic Builder.io content, enable preview mode, and fix 404s caused by static…

⚡ Next.js Implementation Guides
In-depth Next.js guides covering App Router, RSC, ISR, and deployment. Get code examples, optimization checklists, and prompts to accelerate development.
Related Posts:
I was building a massage therapy website with Next.js 16 and Builder.io CMS when I hit a frustrating wall. Every deployment guide I found recommended using output: export for static builds, but that completely broke my ability to fetch dynamic content from Builder.io. After hours of troubleshooting build errors and 404s on Netlify, I discovered the correct approach: Server-Side Rendering with Netlify's serverless functions. This guide walks you through the exact process I developed to get it working.
Understanding the Core Problem
When you deploy Next.js to Netlify, you have two options: static export or server-side rendering. Most guides default to static export because it's simpler and faster to serve. However, if you're using a headless CMS like Builder.io that requires fetching content dynamically at request time, static export won't work.
The issue stems from how Builder.io's preview mode and content fetching work. The fetchOneEntry() function needs to read URL query parameters (searchParams) at request time to detect preview mode and fetch the correct content. This can't happen during a static build—it must happen when someone visits your site. That's why you need Server-Side Rendering.
Step 1: Remove Static Export from Your Configuration
First, we need to make sure your Next.js configuration doesn't force static export. This is the root cause of most deployment failures with CMS integrations.
// File: next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
turbopack: {},
};
export default nextConfig;
The key here is the absence of output: 'export'. By leaving this out, Next.js defaults to SSR mode, which allows your application to render pages on-demand when users request them. The turbopack: {} configuration enables Turbopack (Next.js 16's default bundler) without any custom configuration—Netlify will handle the heavy lifting.
If you previously had output: 'export' in your config, remove it completely. This single change is what allows Netlify to set up serverless functions for your application.
Step 2: Set Up Your Page Component for Dynamic Rendering
Your homepage needs to be an async Server Component that can fetch content dynamically from Builder.io. Here's the correct setup:
// File: src/app/page.tsx
import {
Content,
fetchOneEntry,
getBuilderSearchParams,
isPreviewing,
} from "@builder.io/sdk-react";
import type { Metadata } from "next";
interface PageProps {
searchParams: Promise<Record<string, string>>;
}
const PUBLIC_API_KEY = process.env.NEXT_PUBLIC_BUILDER_IO_PUBLIC_KEY!;
export const metadata: Metadata = {
title: "Your Site Title",
description: "Your site description",
};
export const dynamic = 'force-dynamic';
export default async function HomePage(props: PageProps) {
const urlPath = "/";
const searchParams = await props.searchParams;
const content = await fetchOneEntry({
options: getBuilderSearchParams(searchParams),
apiKey: PUBLIC_API_KEY,
model: "page",
userAttributes: { urlPath },
});
const canShowContent = content || isPreviewing(searchParams);
if (!canShowContent) {
return (
<div className="min-h-screen flex items-center justify-center bg-white">
<div className="text-center max-w-md mx-auto p-8">
<h1 className="text-3xl font-bold text-gray-900 mb-4">
Welcome to Your Site
</h1>
<p className="text-gray-600 mb-6">
This page is powered by Builder.io and is currently being set up.
</p>
</div>
</div>
);
}
return (
<Content
content={content}
apiKey={PUBLIC_API_KEY}
model="page"
/>
);
}
The crucial lines here are export const dynamic = 'force-dynamic' and const searchParams = await props.searchParams. These tell Next.js that this page cannot be statically rendered—it must be rendered on every request. This is necessary because Builder.io's preview parameters change based on the URL, and we need to detect those at runtime.
Also note: we've removed any imports of @builder.io/widgets which can cause bundling issues with Turbopack. If you need widgets, they'll be loaded dynamically through Builder.io's content model.
Step 3: Configure Netlify with the Next.js Plugin
Netlify has an official plugin that handles all the complexity of running Next.js applications with serverless functions. This is what transforms your build into something Netlify can execute.
# File: netlify.toml
[build]
command = "pnpm build"
publish = ".next"
[[plugins]]
package = "@netlify/plugin-nextjs"
The build section tells Netlify:
- command: Use
pnpm buildto compile your Next.js application (adjust tonpm run buildif you use npm) - publish: Deploy the
.nextfolder which contains your compiled application
The [[plugins]] section activates the Netlify Next.js plugin. This plugin automatically creates serverless functions for your dynamic pages and configures the routing to work correctly on Netlify's infrastructure.
Step 4: Install the Netlify Plugin Locally
You need to install the plugin as a dev dependency so Netlify knows it exists when building:
pnpm add -D @netlify/plugin-nextjs
This adds the package to your package.json, and when you push to Git, Netlify will install it during the build process. The plugin will then do the magic of converting your .next build output into serverless functions.
Step 5: Configure Environment Variables on Netlify
Your Builder.io API key needs to be available during runtime. Since environment variables in .env files are never pushed to production for security reasons, you must set them directly in Netlify.
Go to your Netlify dashboard:
- Select your site
- Navigate to Site settings → Build & deploy → Environment
- Click Add environment variable
- Set the variable name to
NEXT_PUBLIC_BUILDER_IO_PUBLIC_KEY - Paste your public API key from Builder.io as the value
The NEXT_PUBLIC_ prefix is crucial—it tells Next.js to make this variable available to your application code (both server and client). Without this prefix, the variable won't be accessible.
Step 6: Push to Git and Deploy
Once your code is ready, push everything to your Git repository:
git add .
git commit -m "Configure Next.js 16 for Netlify deployment with Builder.io"
git push origin main
Netlify automatically detects the push and starts building your application. During the build:
- It installs dependencies (including the
@netlify/plugin-nextjsplugin) - Runs
pnpm buildto compile your Next.js application - The plugin converts your application into serverless functions
- Netlify deploys the functions and static assets
You can watch the build progress in your Netlify dashboard under Deploys. Look for the build log to confirm the plugin ran successfully—you should see output about creating functions.
Troubleshooting Common Issues
Getting 404 errors after deployment? This usually means either the plugin didn't run or your environment variable isn't set. Check:
- The build log shows "0 new function(s) to upload"? The plugin didn't run. Make sure your
netlify.tomlfile was pushed to Git. - Your page renders but has no content? Check that your
NEXT_PUBLIC_BUILDER_IO_PUBLIC_KEYis set in Netlify's environment variables and the build used the updated config.
Build failing with createContext is not a function? This was likely caused by importing @builder.io/widgets directly. Remove that import and let Builder.io load widgets through your content model instead.
Still seeing 404 on the homepage? Ensure you have at least one page published in Builder.io with the URL set to /. Without published content, there's nothing for the application to render.
What You've Now Accomplished
You've set up a Next.js 16 application that:
- Uses Server-Side Rendering to dynamically fetch content from Builder.io
- Supports preview mode so you can see unpublished content while editing
- Deploys to Netlify with zero additional configuration beyond the plugin
- Scales automatically with serverless functions—no servers to manage
The key insight here is understanding why static export doesn't work for CMS platforms. By embracing SSR instead of fighting it, you get a more powerful, maintainable deployment that properly supports your content management workflow.
Let me know in the comments if you have questions, and subscribe for more practical development guides.
Thanks, Matija


