{"record":{"id":"722c5203f69d2cee","repo":"remix-run/react-router","slug":"skipping-prerendering-for-resource-route-withou","errorCode":null,"errorMessage":"⚠️ Skipping prerendering for resource route without a loader: ${leafRoute.id}","messagePattern":"⚠️ Skipping prerendering for resource route without a loader: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/react-router-dev/vite/plugin.ts","lineNumber":2515,"sourceCode":"              manifestRoute &&\n              !manifestRoute.hasDefaultExport &&\n              !manifestRoute.hasErrorBoundary;\n\n            if (isResourceRoute) {\n              if (manifestRoute?.hasLoader) {\n                requests.push(\n                  // Prerender a .data file for turbo-stream consumption\n                  createDataRequest(\n                    prerenderPath,\n                    reactRouterConfig,\n                    [leafRoute.id],\n                    true,\n                  ),\n                  // Prerender a raw file for external consumption\n                  createResourceRouteRequest(prerenderPath, reactRouterConfig),\n                );\n              } else {\n                viteConfig.logger.warn(\n                  `⚠️ Skipping prerendering for resource route without a loader: ${leafRoute.id}`,\n                );\n              }\n            } else {\n              let hasLoaders = matches.some(\n                (m) => reactRouterManifest.routes[m.route.id]?.hasLoader,\n              );\n\n              if (hasLoaders) {\n                requests.push(\n                  createDataRequest(prerenderPath, reactRouterConfig, null),\n                );\n              } else {\n                requests.push(\n                  createRouteRequest(prerenderPath, reactRouterConfig),\n                );\n              }\n            }","sourceCodeStart":2497,"sourceCodeEnd":2533,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router-dev/vite/plugin.ts#L2497-L2533","documentation":"During `react-router build` with prerendering enabled, resource routes are only prerendered when their leaf route exports a `loader`: a resource route with no loader has nothing to render or fetch, so both the .data file and the raw file requests are skipped and the Vite logger emits this warning naming the skipped route id. The build continues; only that route's prerendered output is missing.","triggerScenarios":"`prerender: true` or a prerender path list that matches a resource route whose module has no `loader` export (e.g., it only exports headers/builder functions, or was emptied out).","commonSituations":"Converting a UI route into a resource route and deleting the loader while it's still covered by the prerender config; copy-paste prerender paths pointing at the wrong route; a route that only has a clientLoader; file renames leaving stale route ids.","solutions":["Add a `loader` export to the resource route if it should emit prerendered .data/raw files — the loader's return value becomes the prerendered payload","If the route is intentionally loader-less (static file semantics), remove its path from the `prerender` config to silence the warning","Cross-check the route id in the warning against your routes to make sure the prerender entry points at the route you intended (typos and renames often map to the wrong leaf)"],"exampleFix":"// before - app/routes/resource.ts (no loader)\nexport function headers() { return { \"Cache-Control\": \"public\" }; }\n\n// after\nexport async function loader() {\n  return json({ generatedAt: Date.now() });\n}\nexport function headers() { return { \"Cache-Control\": \"public\" }; }","handlingStrategy":"validation","validationCode":"// before building with prerender, confirm covered resource routes export a loader\nimport glob from \"fast-glob\";\nlet files = await glob(\"app/routes/**/*.{ts,tsx}\");\nlet loaderless = files.filter((f) => !/export\\s+(async\\s+)?function\\s+loader|export\\s+const\\s+loader/.test(fs.readFileSync(f, \"utf8\")));\n// cross-reference loaderless routes against your prerender path list before running `react-router build`","typeGuard":"// narrow a route module to \"prerenderable resource route\"\ntype ResourceRouteModule = { loader: Function };\nfunction isResourceRouteWithLoader(mod: unknown): mod is ResourceRouteModule {\n  return typeof (mod as ResourceRouteModule | undefined)?.loader === \"function\";\n}","tryCatchPattern":null,"preventionTips":["When converting a route to a resource route, keep a loader (even a trivial one) if it must be prerendered","Treat prerender config and route shape as one unit: update both in the same change","Scan build logs for 'Skipping prerendering' after route refactors — the warning names the exact route id"],"tags":["prerender","resource-routes","loader","build"],"backgroundTag":"prerender-missing-loader","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}