withastro/astro · error · AstroError
ServerOnlyModule
ServerOnlyModule
Error message
The "astro:config/server" module is only available server-side.
What it means
The `astro:config/server` virtual module is the server-only half of the serialized config. When its `resolveId`/`load` handler runs under the Astro client environment (`environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client`), Astro throws `ServerOnlyModule` to keep server-only config (and any server virtual modules it pulls in) out of client bundles.
Source
Thrown at packages/astro/src/manifest/virtual-module.ts:88
return RESOLVED_VIRTUAL_CLIENT_ID;
}
},
},
load: {
filter: {
id: new RegExp(`^(${RESOLVED_VIRTUAL_SERVER_ID}|${RESOLVED_VIRTUAL_CLIENT_ID})$`),
},
handler(id) {
if (id === RESOLVED_VIRTUAL_CLIENT_ID) {
// astro:config/client inlines values directly from settings instead of
// importing from virtual:astro:manifest to avoid pulling server-only
// virtual modules (virtual:astro:routes, virtual:astro:pages) into the
// client environment where they are not available.
return { code: clientConfigCode };
}
if (id === RESOLVED_VIRTUAL_SERVER_ID) {
if (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
throw new AstroError({
...AstroErrorData.ServerOnlyModule,
message: AstroErrorData.ServerOnlyModule.message(VIRTUAL_SERVER_ID),
});
}
const code = `
import { manifest } from '${SERIALIZED_MANIFEST_ID}'
import { fromRoutingStrategy } from "astro/app";
let i18n = undefined;
if (manifest.i18n) {
i18n = {
defaultLocale: manifest.i18n.defaultLocale,
locales: manifest.i18n.locales,
routing: fromRoutingStrategy(manifest.i18n.strategy, manifest.i18n.fallbackType),
fallback: manifest.i18n.fallback,
domains: manifest.i18n.domains,
};
}View on GitHub (pinned to d081033d5f)
Solutions
- Remove the `astro:config/server` import from any client-reachable module; use `astro:config/client` for client-safe config values.
- Split server-only config consumers into separate files the browser never imports.
- Trace the import graph to find the client entrypoint pulling in the server module and cut the edge.
Example fix
// before — shared util imported on both sides
import { config } from 'astro:config/server'
export function getBase() { return config.base }
// after — client code uses the client-safe module
import { config } from 'astro:config/client'
export function getBase() { return config.base } Defensive patterns
Strategy: validation
Validate before calling
// Static check: ensure no client-reachable file imports astro:config/server. // Use a grep/ESLint rule disallowing 'astro:config/server' outside server-only dirs.
Type guard
null
Try / catch
null
Prevention
- Use astro:config/client for client code; reserve astro:config/server for server-only files.
- Avoid barrel files mixing the two modules.
- Audit the client bundle for server module leakage.
When it happens
Trigger: Importing `astro:config/server` (directly or transitively) from code that resolves in the client environment — client components, `<script>` tags, client directive entrypoints.
Common situations: A shared utility that imports server config being pulled into a client-rendered component; a barrel file re-exporting `astro:config/server`; mixing server and client config imports in one module graph.
Related errors
- EnvPrefixConflictsWithSecret
- ServerOnlyModule
- i18nNotEnabled
- RemoteImageNotAllowed
- UnsupportedImageFormat
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/886b17f8c8fe97fc.
Report an issue: GitHub.