Fix: Sass Error - Undefined Variable
Quick Answer
Fix the Sass undefined variable error caused by @use vs @import migration, variable scope issues, and dart-sass namespace changes with clear solutions.
The Error
You compile your Sass files and get:
Error: Undefined variable.
|
12 | color: $primary-color;
| ^^^^^^^^^^^^^^
src/components/button.scss 12:8 @useOr with older node-sass:
SassError: Undefined variable: "$primary-color"
on line 12 of src/components/button.scssThe variable exists in another file, but Sass can’t find it during compilation.
Why This Happens
Sass variable visibility depends on how you import files. The modern @use rule (introduced in Dart Sass) creates a namespace for each imported file. Variables from @use-imported files aren’t available globally — you must access them through their namespace. This is the most common cause of the error when migrating from @import to @use.
With the legacy @import rule, all variables were global. With @use, they’re scoped. This is intentional — it prevents naming collisions — but it breaks existing code that assumes global access.
Fix 1: Use the Correct Namespace
When you @use a file, its variables are available under a namespace matching the filename:
// _variables.scss
$primary-color: #3b82f6;
$font-size-base: 16px;
// button.scss
@use 'variables';
.button {
// Wrong - no namespace
color: $primary-color;
// Correct - with namespace
color: variables.$primary-color;
font-size: variables.$font-size-base;
}The namespace is the last component of the file path without the extension. For @use 'config/variables', the namespace is variables.
Customize the namespace with as:
@use 'variables' as vars;
.button {
color: vars.$primary-color;
}Or remove the namespace entirely with as *:
@use 'variables' as *;
.button {
color: $primary-color; // Works without namespace
}Common Mistake: Overusing
as *defeats the purpose of@usenamespacing. Reserve it for files you use extensively (like your design tokens). For everything else, keep the namespace to avoid collisions.
Fix 2: Configure @forward for Library Files
If you have an index file that re-exports variables from multiple files, use @forward:
// abstracts/_variables.scss
$primary-color: #3b82f6;
// abstracts/_mixins.scss
@mixin flex-center { display: flex; align-items: center; justify-content: center; }
// abstracts/_index.scss
@forward 'variables';
@forward 'mixins';
// components/button.scss
@use '../abstracts';
.button {
color: abstracts.$primary-color;
@include abstracts.flex-center;
}@forward makes the forwarded module’s members available to anyone who @uses the forwarding file. Without @forward, @use 'abstracts' would only expose members defined directly in _index.scss.
Fix 3: Fix File Import Order
Variables must be defined before they’re used. With @use, the order matters:
// Wrong - using variable before it's available
@use 'components/button'; // Uses $primary-color
@use 'variables'; // Defines $primary-color
// Correct - define first, use second
@use 'variables';
@use 'components/button';However, each file should @use its own dependencies rather than relying on import order in a main file:
// components/_button.scss — self-contained
@use '../variables';
.button {
color: variables.$primary-color;
}This makes each file independent and eliminates order-related issues.
Fix 4: Fix Partial File Naming
Sass partials must start with an underscore. Without it, Sass may not find the file:
styles/
├── _variables.scss ✓ Partial (imported, not compiled alone)
├── variables.scss ✗ Compiled as standalone file
└── main.scssWhen you write @use 'variables', Sass looks for _variables.scss. If the file is named variables.scss without the underscore, Sass treats it as a standalone file, not an importable partial.
Rename your files to include the underscore prefix:
mv variables.scss _variables.scss
mv mixins.scss _mixins.scssFix 5: Migrate from node-sass to Dart Sass
node-sass is deprecated and doesn’t support @use or @forward. If you’re using @import with node-sass, everything is global. But if you switch to Dart Sass without updating your import style, variables break:
# Check which Sass you're using
npx sass --version # Dart Sass
node -e "console.log(require('node-sass').info)" # node-sassMigrate to Dart Sass:
npm uninstall node-sass
npm install sassAfter switching, you have two options:
- Keep using
@import(works but deprecated, will be removed in Dart Sass 3.0) - Migrate to
@use/@forward(recommended)
Use the official migration tool:
npx sass-migrator module style.scssPro Tip: The Sass Migrator tool handles most of the
@importto@useconversion automatically, including adding namespaces and converting variable references. Run it with--dry-runfirst to preview changes.
Fix 6: Fix Load Paths
If your Sass files are in a non-standard directory, Sass may not find them. Configure load paths:
# CLI
sass --load-path=src/styles main.scss output.css
# Webpack (sass-loader)
{
loader: 'sass-loader',
options: {
sassOptions: {
includePaths: [path.resolve(__dirname, 'src/styles')]
}
}
}For Vite:
// vite.config.js
export default {
css: {
preprocessorOptions: {
scss: {
includePaths: ['src/styles']
}
}
}
}With load paths configured, you can use shorter imports:
// Instead of
@use '../../styles/variables';
// You can write
@use 'variables';Fix 7: Fix Variable Scope in Control Structures
Variables defined inside control structures (@if, @each, @for) are local to that block:
// Wrong - $color is scoped to the @if block
@if $theme == 'dark' {
$color: #ffffff;
}
.text { color: $color; } // Error: Undefined variable
// Correct - declare outside, assign inside
$color: #000000;
@if $theme == 'dark' {
$color: #ffffff !global;
}
.text { color: $color; }The !global flag is needed to modify a variable from an outer scope inside a control structure. Without it, Sass creates a new local variable.
For mixin arguments, variables are scoped to the mixin body:
@mixin theme($bg, $text) {
background: $bg;
color: $text;
// $bg and $text don't exist outside this mixin
}Fix 8: Configure Global Variables with @forward ... with
Sometimes you need to override default variables from a library. Use @forward ... with to set configurable defaults:
// _config.scss
$primary-color: #3b82f6 !default;
$border-radius: 4px !default;
// _index.scss
@forward 'config';
// main.scss — override defaults
@use 'index' with (
$primary-color: #ef4444,
$border-radius: 8px
);Variables must be marked with !default to be configurable. The with clause only works with @use, not @forward.
For third-party libraries like Bootstrap:
// Override Bootstrap variables before importing
@use 'bootstrap/scss/bootstrap' with (
$primary: #custom-color,
$enable-shadows: true
);Still Not Working?
Check for typos in variable names. Sass variables are case-sensitive.
$Primary-Colorand$primary-colorare different variables.Verify file extensions. Sass processes
.scssand.sassdifferently. Don’t mix syntaxes in@usewithout specifying the extension.Clear your build cache. Stale cached files can cause phantom errors. Delete
.sass-cache/,node_modules/.cache/, and your output directory.Check for circular imports. If file A uses file B and file B uses file A, Sass may fail silently. Restructure to break the cycle — extract shared variables into a separate file.
Verify your bundler configuration. Webpack, Vite, and other bundlers resolve Sass imports differently. Check that your sass-loader or preprocessor options match your file structure.
Test with the Sass CLI directly. Run
npx sass input.scss output.cssto isolate whether the issue is with Sass itself or your build tool’s configuration.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: NativeWind Not Working — Styles Not Applying, Dark Mode Broken, or Metro Bundler Errors
How to fix NativeWind issues — Tailwind CSS for React Native setup, Metro bundler configuration, className prop, dark mode, responsive styles, and Expo integration.
Fix: Tamagui Not Working — Styles Not Applying, Compiler Errors, or Web/Native Mismatch
How to fix Tamagui UI kit issues — setup with Expo, theme tokens, styled components, animations, responsive props, media queries, and cross-platform rendering.
Fix: Mantine Not Working — Styles Not Loading, Theme Not Applying, or Components Broken After Upgrade
How to fix Mantine UI issues — MantineProvider setup, PostCSS configuration, theme customization, dark mode, form validation with useForm, and Next.js App Router integration.
Fix: View Transitions API Not Working — No Animation Between Pages, Cross-Document Transitions Failing, or Fallback Missing
How to fix View Transitions API issues — same-document transitions, cross-document MPA transitions, view-transition-name CSS, Next.js and Astro integration, custom animations, and browser support.