How to Fix: Api route and sitemap are 0kb on build
Your build is not actually broken when the API route and sitemap output show up as 0 kB in a Next.js build tree. In this case, the confusing output is a side effect of how Next.js treats route handlers and metadata routes during compilation, especially in the App Router. The fix is usually about verifying runtime behavior, making the sitemap implementation compatible with Next.js expectations, and understanding what the build report is really measuring.
Why the build shows 0 kB
In the linked reproduction, the issue appears after running the production build and inspecting the output tree. Routes such as an API endpoint or sitemap can display 0 kB, which looks like an empty file or a failed build artifact. In practice, this usually means Next.js did not emit a client-side JavaScript bundle for that route because the route is handled on the server, generated as metadata, or resolved dynamically at request/build time.
That is especially common with:
- app/api/…/route.ts endpoints
- app/sitemap.ts metadata routes
- server-only code with no browser bundle
- build output summaries that report JS payload size, not the literal response body size
So if your build tree says 0 kB, that does not automatically mean the route response is empty.
Understanding the Root Cause
Next.js build output can be misleading if you read it as a file size report. For App Router projects, the build tree often shows the size of the JavaScript needed for a route, not the final response content returned by the server.
That matters for two route types in this issue:
- API routes: A route handler such as
app/api/example/route.tsruns on the server. It typically sends aResponseorNextResponse. Since no client bundle is needed, the build report may show 0 kB. - Sitemap routes: A sitemap implemented with
app/sitemap.tsis a metadata route. Next.js generates it from a function return value, not from a static client asset. Again, the build tree may show 0 kB because there is no browser JavaScript attached to it.
In other words, the root cause is usually a mismatch between what developers expect the build tree to represent and what Next.js is actually reporting.
There is a second technical detail that can create real sitemap problems: if the sitemap is implemented using the wrong format, incorrect exports, unsupported response handling, or dynamic data patterns that Next.js cannot optimize correctly, the route may behave unexpectedly even if the build output itself is normal.
Step-by-Step Solution
The safest approach is to validate both the implementation and the runtime output.
1. Use the correct sitemap implementation for the App Router
If you are using Next.js App Router, your sitemap should usually live at app/sitemap.ts and export a default function returning an array of URL objects.
import type { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://example.com',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 1,
},
{
url: 'https://example.com/patterns',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
]
}
This is the preferred pattern because Next.js recognizes it as a metadata route and generates the sitemap correctly.
2. Use proper route handlers for API endpoints
For API routes in the App Router, define them under app/api/.../route.ts and return a server response explicitly.
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json({ ok: true })
}
If this route shows 0 kB in the build output, that is usually expected because it is a server route, not a client bundle.
3. Verify the route output after build
Do not rely only on the build tree. Start the production server and request the route directly.
yarn build
yarn start
Then test:
If the sitemap renders XML and the API route returns data, the 0 kB label is just a build-report artifact.
4. If your sitemap depends on dynamic content, keep the return format valid
If you fetch database or CMS content, still return a valid MetadataRoute.Sitemap structure.
import type { MetadataRoute } from 'next'
async function getPatterns() {
return [
{ slug: 'hero-sections', updatedAt: '2024-01-10' },
{ slug: 'pricing-tables', updatedAt: '2024-01-11' },
]
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const patterns = await getPatterns()
return [
{
url: 'https://example.com',
lastModified: new Date(),
},
...patterns.map((pattern) => ({
url: `https://example.com/patterns/${pattern.slug}`,
lastModified: new Date(pattern.updatedAt),
})),
]
}
This keeps the route compatible with Next.js metadata processing.
5. Do not treat build tree size as response payload size
A critical takeaway for this issue: the build summary is often reporting bundled JavaScript size or route classification, not the literal bytes of the XML or JSON your route returns at runtime.
So this:
/sitemap.xml 0 B
/api/example 0 B
often means:
- No client JavaScript is shipped for that route
- The route is server-generated
- The route may still be functioning perfectly
6. If you need a truly static sitemap file, generate it explicitly
If your goal is not just a working metadata route, but an actual static file in the final output, use a static generation strategy or a sitemap generation tool during build. For example, some teams generate public/sitemap.xml as part of CI/CD instead of relying on runtime metadata routes.
// example script idea
// generate-sitemap.js
const fs = require('fs')
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
</url>
</urlset>`
fs.writeFileSync('public/sitemap.xml', xml)
That is only necessary if your deployment or reporting process specifically requires a physical static asset.
Common Edge Cases
- Wrong file location: A sitemap in the wrong directory, such as mixing
pagesandappconventions incorrectly, can prevent Next.js from recognizing it as a metadata route. - Incorrect export shape:
app/sitemap.tsshould export a default function returning the expected structure. Returning raw XML directly from this file is not the normal App Router pattern. - Environment-specific URLs: Hardcoded localhost or missing production base URLs can make the sitemap appear valid while containing incorrect links.
- Dynamic rendering confusion: If your route fetches uncached data, Next.js may classify it differently during build. That still does not mean the route is empty, but it can affect optimization behavior.
- Deployment platform differences: Some platforms display build artifacts differently from local output. Always test the deployed endpoint directly.
- Using route handlers for sitemap unnecessarily: If you implement sitemap generation in
app/sitemap.xml/route.tsinstead ofapp/sitemap.ts, it can work, but you lose the cleaner metadata route integration.
FAQ
Why does my sitemap show 0 kB in build output but still work in the browser?
Because the build output is usually showing bundle size, not the final XML response body. A metadata sitemap often ships no client JavaScript, so it appears as 0 kB.
Is 0 kB for an API route a bug in Next.js?
Usually no. For a server-only route handler, Next.js may report 0 kB because there is no browser bundle attached to that endpoint. The real test is whether the route returns the expected response at runtime.
Should I replace app/sitemap.ts with a static public/sitemap.xml file?
Only if you specifically need a physical static file. For most App Router projects, app/sitemap.ts is the correct and recommended solution.
The practical resolution for this issue is simple: treat the 0 kB build output as informational, not as proof of failure, then verify the sitemap and API route by running the production server. If the routes respond correctly and your sitemap uses the proper App Router metadata API, the build is behaving as expected.