CI/CD Pipelines
Considerations before setting up CI/CD pipelines
When deploying Next.js applications that use Cloudflare D1 databases, you may encounter build failures during CI/CD processes. This section explains the architectural limitations and provides solutions for successful deployments.
The Problem
Next.js applications using Static Site Generation (SSG) that attempt to access D1 databases during the build process will fail in CI/CD environments, including both GitHub Actions and Cloudflare Workers Builds.
Why This Happens
The issue stems from a fundamental architectural separation:
- Build Environment: Runs in standard Node.js (GitHub Actions runners, Cloudflare build infrastructure)
- Runtime Environment: Runs in Cloudflare Workers with access to D1 bindings
During next build, Next.js attempts to pre-render pages that require database access, but D1 bindings are only available in the Workers runtime environment.
This limitation affects both GitHub Actions deployments and Cloudflare's native GitHub integration. The build process runs in Node.js regardless of the deployment method.
You'll typically see errors like:
Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error
Error: Failed query: select * from "users"Or:
✘ [ERROR] getCloudflareContext() can only be used in a Cloudflare Workers environmentSolutions
Option 1: Dynamic Rendering (Recommended)
Convert static pages to dynamic rendering for database-dependent content:
// Force dynamic rendering for database-dependent pages
export const dynamic = 'force-dynamic'
export default async function HomePage() {
const users = await getUsers() // Now runs at request time
return (
<div>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
)
}This can seem counter-intuitive to performance, but given the extraordinary performance of Cloudflare (zero cold-starts), this can quickly mitigate performance concerns.
Option 2: Client-Side Data Fetching
Move database calls to API routes and fetch client-side:
// app/api/users/route.ts
export async function GET() {
const users = await getUsers()
return Response.json(users)
}
// app/page.tsx
'use client'
export default function HomePage() {
const [users, setUsers] = useState([])
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(setUsers)
}, [])
return <div>{/* Render users */}</div>
}This is not a good solution, and I hesitate to present it, but this would work. Vercel recommend using a Data Access Layer approach when thinking about your Data Handling Model and security. Anything done client side can be open to bad actors, and as such it's typically better to prefer doing as much on the server as possible.
Configuring CI/CD with Cloudflare
If you wish to continue to configure a CI/CD pipeline using Cloudflare's native build system, see the Automatic Deployments page for a brief tutorial.
FAQs
How is this guide?
Last updated on