{"record":{"id":"7a3725dfacd6a466","repo":"withastro/astro","slug":"astro-components-cannot-be-used-in-the-browser-tr","errorCode":null,"errorMessage":"Astro components cannot be used in the browser.\nTried to render \"${filename}\".","messagePattern":"Astro components cannot be used in the browser\\.\nTried to render \"(.+?)\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/vite-plugin-astro/index.ts","lineNumber":273,"sourceCode":"\t\t\t\t\t\texclude: [specialQueriesRE, /(?:\\?|&)astro(?:&|=|$)/],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync handler(source, id) {\n\t\t\t\t\tconst parsedId = parseAstroRequest(id);\n\n\t\t\t\t\tif (!parsedId.filename.endsWith('.astro')) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst filename = normalizePath(parsedId.filename);\n\n\t\t\t\t\t// If an Astro component is imported in code used on the client, we return an empty\n\t\t\t\t\t// module so that Vite doesn’t bundle the server-side Astro code for the client.\n\t\t\t\t\tif (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcode: `export default import.meta.env.DEV\n\t\t\t\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t\t\t\t'Astro components cannot be used in the browser.\\\\nTried to render \"${filename}\".'\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {};`,\n\t\t\t\t\t\t\tmoduleType: 'ts',\n\t\t\t\t\t\t\tmeta: { vite: { lang: 'ts' } },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst transformResult = await compile(source, filename);\n\n\t\t\t\t\tconst astroMetadata: AstroPluginMetadata['astro'] = {\n\t\t\t\t\t\t// Remove Astro components that have been mistakenly given client directives\n\t\t\t\t\t\t// We'll warn the user about this later, but for now we'll prevent them from breaking the build\n\t\t\t\t\t\tclientOnlyComponents: transformResult.clientOnlyComponents.filter(notAstroComponent),\n\t\t\t\t\t\thydratedComponents: transformResult.hydratedComponents.filter(notAstroComponent),\n\t\t\t\t\t\tserverComponents: transformResult.serverComponents,\n\t\t\t\t\t\tscripts: transformResult.scripts,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/vite-plugin-astro/index.ts#L255-L291","documentation":"Astro components are server-only — they compile to server rendering code. When Vite's client environment encounters an import of an .astro file, Astro substitutes an empty module whose default export (in dev) is a function that throws this error when called, turning 'I imported a server component into browser code' into a loud failure at the call site. Production builds return {} instead, so this surfaces mainly during development.","triggerScenarios":"import Card from './Card.astro' inside a <script> tag (which runs in the browser) or inside a framework island (.tsx/.svelte/.vue) that hydrates on the client; transitively importing an .astro file from client-side shared code; trying to render an Astro component from a React/Vue component at runtime.","commonSituations":"Attempting to use an Astro component inside a React island; sharing a module that re-exports values computed in .astro frontmatter; porting server-component patterns from other frameworks into client code.","solutions":["Remove the .astro import from client-executed code; render the Astro component on the server and pass its output into the island via props, slots, or set:html","Replace the Astro component inside the island with a framework component (.tsx/.vue/etc.)","If only markup is needed, pre-render it in the .astro page and inject it with set:html"],"exampleFix":"// before — src/islands/Counter.ts (hydrated in the browser)\nimport Card from '../components/Card.astro';\nexport function mount(el) {\n\trender(<Card />, el);\n}\n\n// after — render on the server, pass HTML through\n// page.astro\n<Counter el={document.querySelector('#x')}>\n\t<Card />  {/* rendered server-side, delivered as children */}\n</Counter>","handlingStrategy":"validation","validationCode":"// scripts/check-client-astro-imports.mjs — run in CI to fail before the browser does\nimport { execSync } from 'node:child_process';\ntry {\n\tconst out = execSync(\n\t\t\"grep -rn \\\"from ['\\\\\\\"].*\\\\.astro['\\\\\\\"]\\\" src --include='*.ts' --include='*.tsx' --include='*.vue' --include='*.svelte'\",\n\t\t{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },\n\t);\n\tif (out.trim()) {\n\t\tconsole.error('Client-side code imports .astro components:\\n' + out);\n\t\tprocess.exit(1);\n\t}\n} catch (e) {\n\tif (e.stdout) { console.error('Client-side code imports .astro components:\\n' + e.stdout); process.exit(1); }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep .astro imports out of <script> tags and framework islands — Astro components render server-side only","Pass pre-rendered markup into islands via children/slots or set:html instead of importing components","Add a CI grep for .astro imports in client-side source files to catch regressions early"],"tags":["client-bundle","astro-components","islands","dev"],"backgroundTag":"server-component-in-client-bundle","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}