{"record":{"id":"3ee4412df2fd358e","repo":"withastro/astro","slug":"serveronlymodule","errorCode":"ServerOnlyModule","errorMessage":"The \"astro:content\" module is only available server-side.","messagePattern":"The \"astro:content\" module is only available server-side\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/content/vite-plugin-content-virtual-mod.ts","lineNumber":431,"sourceCode":"\nasync function generateContentEntryFile({\n\tsettings,\n\tisClient,\n}: {\n\tsettings: AstroSettings;\n\tfs: typeof nodeFs;\n\tisClient: boolean;\n}) {\n\tconst contentPaths = getContentPaths(\n\t\tsettings.config,\n\t\tundefined,\n\t\tsettings.config.legacy?.collectionsBackwardsCompat,\n\t);\n\tconst relContentDir = rootRelativePath(settings.config.root, contentPaths.contentDir);\n\n\tlet virtualModContents: string;\n\tif (isClient) {\n\t\tthrow new AstroError({\n\t\t\t...AstroErrorData.ServerOnlyModule,\n\t\t\tmessage: AstroErrorData.ServerOnlyModule.message('astro:content'),\n\t\t});\n\t} else {\n\t\tvirtualModContents = nodeFs\n\t\t\t.readFileSync(contentPaths.virtualModTemplate, 'utf-8')\n\t\t\t.replace('@@CONTENT_DIR@@', relContentDir)\n\t\t\t.replace(\n\t\t\t\t'/* @@LIVE_CONTENT_CONFIG@@ */',\n\t\t\t\tcontentPaths.liveConfig.exists\n\t\t\t\t\t? // Dynamic import so it extracts the chunk and avoids a circular import\n\t\t\t\t\t\t`const liveCollections = (await import(${JSON.stringify(fileURLToPath(contentPaths.liveConfig.url))})).collections;`\n\t\t\t\t\t: 'const liveCollections = {};',\n\t\t\t);\n\t}\n\n\treturn virtualModContents;\n}","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/withastro/astro/blob/157c500c38faa7ecf1251adbaeefcd109470d75c/packages/astro/src/content/vite-plugin-content-virtual-mod.ts#L413-L449","documentation":"The astro:content virtual module — getCollection, getEntry, render, and config types — is generated for server bundles only. When the module is requested from a client environment build, such as a hydrated island importing it, the plugin throws ServerOnlyModule to stop the dependency on server-only infrastructure from reaching the browser bundle.","triggerScenarios":"import { getEntry } from 'astro:content' inside a component hydrated with client:load/client:visible (React, Svelte, Vue, Solid); a <script> processed for the browser importing a module that imports astro:content; framework client entrypoints re-exporting a file that pulls it in.","commonSituations":"Moving data fetching into a shared UI component that later gets hydrated; shared constants files re-exporting from astro:content; refactoring islands so previously server-only code lands in the client graph.","solutions":["Fetch entries in an .astro page or component and pass plain serializable data as props into the island.","Remove astro:content imports from any file reachable from a client: directive or an inline <script>.","For type-only usage, use import type so the import is erased at compile time.","Split shared modules into server-only and client-safe variants so data access stays on the server."],"exampleFix":"// before: Island.jsx hydrated with client:load\nimport { getEntry } from 'astro:content';\nexport default function Island({ slug }) { /* uses getEntry */ }\n\n// after: page.astro fetches server-side and passes data\n---\nimport { getEntry } from 'astro:content';\nimport Island from '../components/Island.jsx';\nconst post = await getEntry('blog', Astro.params.slug);\n---\n<Island client:load post={post.data} />","handlingStrategy":"validation","validationCode":"// Static check: no file under a client-hydrated component dir may import astro:content\nimport { readdir, readFile } from 'node:fs/promises';\nfor (const file of await readdir('src/components/islands', { recursive: true })) {\n  if (!/\\.(jsx|tsx|svelte|vue)$/.test(String(file))) continue;\n  const src = await readFile(`src/components/islands/${file}`, 'utf8');\n  if (src.includes('astro:content')) console.error(`astro:content imported in island ${file}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch content server-side in .astro files and pass data as props to islands.","Use import type { CollectionEntry } for types — type-only imports are erased.","Keep shared client/server modules split so server-only data access cannot leak into the client graph."],"tags":["content-collections","ssr","client-bundle","islands","server-only"],"backgroundTag":"server-only-module-import","analyzedSha":"157c500c38faa7ecf1251adbaeefcd109470d75c","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}