Stopping the Global Scope Leak: Migrating from @import to @use in Sass
Stop fighting global scope collisions in Sass. Learn how @use and @forward replace @import to provide namespacing, private members, and configurable design tokens.
18 Jul 2025, 03:22 UTC

The Problem with Global Scope
For years, the @import rule was the only way to organize Sass. However, @import has a fundamental flaw: it makes everything global. If you import a _variables.scss file in ten different components, Sass executes that file ten times. More dangerously, if two different imported files both define a variable named $primary-color, the last one imported wins, silently overwriting the previous value across your entire application.
The @use rule, introduced in Dart Sass, solves this by treating stylesheets as modules. Instead of dumping everything into a single global bucket, @use loads a file exactly once and keeps its members namespaced to the file name.
Namespacing and Encapsulation
When you load a module with @use 'colors', you no longer access $primary directly. Instead, you use colors.$primary. This creates a clear trace of where a value originates, making debugging significantly faster in large codebases.
This system also introduces private members. By starting a variable, function, or mixin name with a hyphen (-) or underscore (_), you prevent it from being accessed outside that specific file. This allows you to create internal helper functions that don't clutter the public API of your design system.
Managing Libraries with @forward
If you are building a library or a theme, you likely have a folder of partials that you want users to access via a single entry point. The @forward rule allows you to gather multiple modules and expose them as a single package.
For example, an _index.scss file can use @forward 'colors' and @forward 'typography'. When a consumer calls @use 'theme', they get access to both the color and typography members without needing to know the internal folder structure of your library.
Worked Example: Configurable Design Tokens
One of the most powerful features of the module system is the ability to configure a module at the moment it is loaded. This requires the use of the !default flag in the source module.
1. Define the module (_tokens.scss)
// _tokens.scss
$spacing-unit: 8px !default;
$brand-color: blue !default;
@mixin rounded-corner {
border-radius: $spacing-unit;
}
2. Consume and configure the module (main.scss)
Run this compilation using the Dart Sass compiler. Note that the configuration happens within the @use statement itself.
// main.scss
@use 'tokens' with (
$spacing-unit: 12px
);
.card {
// Access variable via namespace
padding: tokens.$spacing-unit;
// Use mixin via namespace
@include tokens.rounded-corner;
}
Expected Result: The .card class will have a padding of 12px and a border-radius of 12px. The $brand-color remains blue because it was not overridden.
Trade-offs and Limitations
The transition to modules is not a simple find-and-replace operation. There are three primary constraints to consider:
- Compiler Requirement: Only Dart Sass supports
@useand@forward. If your project relies onnode-sassorLibSass, you must migrate your compiler first, as these legacy versions will throw errors when encountering module rules. - Configuration Order: You can only configure a module using
with (...)the first time it is loaded in the compilation graph. Subsequent attempts to configure the same module will result in a compiler error. - Built-in Modules: Global functions like
color.adjustormath.divhave been moved into built-in modules (e.g.,sass:math). You must now@use 'sass:math'to access these functions, and some function signatures have changed.
Verification and Rollback
To verify your migration, run sass --version to ensure you are on a modern Dart Sass release. You can test for scope leaks by intentionally defining a variable with the same name in two different modules; if you are using @use, both should be accessible via their respective namespaces without conflict.
Rollback: Because @use changes how variables are referenced (adding namespaces), rolling back requires reverting both the @use declarations and all corresponding variable calls (e.g., changing tokens.$spacing back to $spacing) and returning to @import.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.