withastro/astro · error · Error

Astro components cannot be used in the browser. Tried to ren

Error message

Astro components cannot be used in the browser.
Tried to render "${filename}".

What it means

Thrown at runtime (in dev) when an Astro component (`.astro`) is imported into client-side code. Astro components are server-rendered; they cannot run in the browser. The plugin detects imports of `.astro` files in the client environment and returns a stub module that throws this error when the stub default export is invoked in dev, or an empty object in production builds.

Source

Thrown at packages/astro/src/vite-plugin-astro/index.ts:273

						exclude: [specialQueriesRE, /(?:\?|&)astro(?:&|=|$)/],
					},
				},
				async handler(source, id) {
					const parsedId = parseAstroRequest(id);

					if (!parsedId.filename.endsWith('.astro')) {
						return;
					}

					const filename = normalizePath(parsedId.filename);

					// If an Astro component is imported in code used on the client, we return an empty
					// module so that Vite doesn’t bundle the server-side Astro code for the client.
					if (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
						return {
							code: `export default import.meta.env.DEV
									? () => {
											throw new Error(
												'Astro components cannot be used in the browser.\\nTried to render "${filename}".'
											);
										}
									: {};`,
							moduleType: 'ts',
							meta: { vite: { lang: 'ts' } },
						};
					}

					const transformResult = await compile(source, filename);

					const astroMetadata: AstroPluginMetadata['astro'] = {
						// Remove Astro components that have been mistakenly given client directives
						// We'll warn the user about this later, but for now we'll prevent them from breaking the build
						clientOnlyComponents: transformResult.clientOnlyComponents.filter(notAstroComponent),
						hydratedComponents: transformResult.hydratedComponents.filter(notAstroComponent),
						serverComponents: transformResult.serverComponents,
						scripts: transformResult.scripts,

View on GitHub (pinned to d081033d5f)

Solutions

  1. Move the shared logic/constants into a plain `.ts` or `.js` module and import that from both the component and the client script.
  2. If you need client-side interactivity, use a framework component (React/Vue/Svelte/Solid) with `client:*` directives instead of an `.astro` file.
  3. If you only needed types, import the type via `import type` (erased at runtime) or define types in a separate `.d.ts`.

Example fix

// before — client.ts
import MyComponent from '../components/MyComponent.astro';

// after
import { sharedConstants } from '../utils/shared.ts';
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure no .astro import appears in client-resolved modules.
// Run: grep -rn "from '.*\\.astro'" src/ then verify each importer is server-only.

Type guard

// ESLint rule of thumb: disallow importing .astro from files under src/scripts or client entrypoints.
// no-restricted-syntax: reject ImportDeclaration whose source ends with .astro in client contexts.

Prevention

When it happens

Trigger: Importing a `.astro` component from a `<script>` block (client-side), a client-side `.ts`/`.js` file, or any module resolved by the `client` Vite environment. The throw happens when the default export (a render function) is called in dev.

Common situations: Trying to use an Astro component as a client-side widget or web component. Importing a shared `.astro` layout/component from a client script for its types or constants. Confusing Astro components (server-only) with framework components (React/Vue/Svelte) which can hydrate.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/7a3725dfacd6a466. Report an issue: GitHub.