sveltejs/kit · error · Error
Cannot import `$app/*` modules other than `$app/env` inside
Error message
Cannot import `$app/*` modules other than `$app/env` inside `src/env`
What it means
Modules in src/env can only import `$app/env`; importing any other `$app/*` module (like $app/navigation or $app/stores) is prohibited because src/env.js is loaded in a build-time context without the full app runtime. When the dynamic import fails with ERR_MODULE_NOT_FOUND for a `$app` module, SvelteKit rethrows with this clearer message.
Source
Thrown at packages/kit/src/core/env.js:103
if (!variables || typeof variables !== 'object') {
throw new Error(`${file} must export a variables object`);
}
// validate
for (const name of Object.keys(variables)) {
if (!valid_identifier.test(name) || reserved.has(name)) {
throw new Error(`Invalid environment variable name ${JSON.stringify(name)}`);
}
}
} catch (e) {
const error = /** @type {any} */ (e || {});
if (
error.code === 'ERR_MODULE_NOT_FOUND' &&
error.message?.includes(`Cannot find module '$app`)
) {
throw new Error(
`Cannot import \`$app/*\` modules other than \`$app/env\` inside \`src/env\``,
{ cause: e }
);
}
throw error;
} finally {
await server.close();
}
return { variables, deps };
}
/**
* Creates the `<sveltekit:generated>/env/*` modules, keyed by path relative to `dir`. Every module
* derives from one pass over `variables`, so an inlined value is validated once per build.
* @param {ValidatedConfig} config
* @param {Record<string, EnvVarConfig<any>> | null} variablesView on GitHub (pinned to 03f1687fe6)
Solutions
- Remove all `$app/*` imports other than `$app/env` from src/env.js and everything it imports.
- Move shared logic that needs $app modules out of the src/env import graph.
- Use only plain Node-compatible code and $app/env inside src/env.js.
Example fix
// before (src/env.js)
import { dev } from '$app/environment';
import { goto } from '$app/navigation';
export const variables = {};
// after
import { dev } from '$app/environment';
export const variables = {}; Defensive patterns
Strategy: validation
Validate before calling
// scan src/env.js and its local imports for forbidden $app modules
const src = await fs.readFile('src/env.js', 'utf8');
const bad = src.match(/\$app\/(?!env\b)[\w-]+/g);
if (bad) throw new Error(`Forbidden imports in src/env.js: ${bad.join(', ')}`); Try / catch
try {
await build();
} catch (e) {
if (String(e.message).includes('Cannot import `$app/*` modules')) {
console.error('src/env.js import graph must only use $app/env — refactor the import out');
} else throw e;
} Prevention
- Keep src/env.js dependency-free except for $app/env and plain Node modules.
- Audit any shared module before importing it into src/env.js for transitive $app imports.
- Only $app/environment (and $app/env) are permitted in the src/env context.
When it happens
Trigger: src/env.js (or its imports) containing `import { goto } from '$app/navigation'` or any non-env `$app` import; transitively importing an app module that itself imports $app/* modules.
Common situations: Reusing a shared module inside src/env.js that pulls in client-side app code; attempting to derive env validation from app stores.
Related errors
- ${file} must export a variables object
- `defineEnvVars` has moved — import it from `@sveltejs/kit/en
- `$app/environment` is deprecated, use `$app/env` instead
- `$env/dynamic/private` is deprecated, use `$app/env/private`
- `$env/dynamic/public` is deprecated, use `$app/env/public` i
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/d2e4fa07080a0ea6.
Report an issue: GitHub.