Skip to content

Fix Next.js prerender error on sitemap.xml when database is unavailable

fix

Next.js build fails prerendering /sitemap.xml because the route queries a database not available at build time

nextjsdatabasesitemapprerender
25 views

Problem

Running next build fails during the prerender phase when the sitemap route queries a database that is not reachable at build time:

Error occurred prerendering page "/sitemap.xml". Read more: https://nextjs.org/docs/messages/prerender-error

Error: No database connection string was provided to `neon()`. You can either set
the POSTGRES_URL environment variable or pass a connection string to `neon()`.

Export encountered errors on following paths:
  /sitemap.xml/[[...__metadata_id__]]/route

The sitemap route that triggers this error:

// app/sitemap.ts
import { db } from "@/lib/db";
import { posts } from "@/lib/schema";

export default async function sitemap() {
  const allPosts = await db.select().from(posts);

  return allPosts.map((post) => ({
    url: `https://example.com/posts/${post.slug}`,
    lastModified: post.updatedAt,
  }));
}

Solution

Option 1: Mark the route as dynamic (recommended)

Add the dynamic route segment config to force the sitemap to render at request time instead of build time:

// app/sitemap.ts
import { db } from "@/lib/db";
import { posts } from "@/lib/schema";

export const dynamic = "force-dynamic";

export default async function sitemap() {
  const allPosts = await db.select().from(posts);

  return allPosts.map((post) => ({
    url: `https://example.com/posts/${post.slug}`,
    lastModified: post.updatedAt,
  }));
}

Option 2: Wrap the database call in a try-catch with a fallback

// app/sitemap.ts
import { db } from "@/lib/db";
import { posts } from "@/lib/schema";

export default async function sitemap() {
  try {
    const allPosts = await db.select().from(posts);

    return allPosts.map((post) => ({
      url: `https://example.com/posts/${post.slug}`,
      lastModified: post.updatedAt,
    }));
  } catch {
    return [];
  }
}

Why It Works

By default, Next.js App Router treats routes without dynamic APIs (cookies(), headers(), searchParams) as static and prerenders them at build time. If the route queries a database whose connection string is not available in the build environment, the prerender fails.

Setting export const dynamic = 'force-dynamic' tells Next.js to skip prerendering for that route. The sitemap is generated on each request at runtime when the database connection is available. This adds minimal overhead since sitemaps are typically cached by CDNs.

Context

  • Next.js 14+ App Router with the built-in sitemap.ts convention
  • Applies to any database ORM or client: Drizzle, Prisma, Neon serverless driver, Supabase
  • Also affects other dynamic routes that query external services at build time (RSS feeds, robots.ts, og:image routes)
  • The try-catch approach (Option 2) still prerenders with an empty result, which may cause SEO gaps until the first runtime request
About this share
Contributormblode
Repositorymblode/shares
CreatedFeb 9, 2026
Environmentnextjs 14+
View on GitHub