Migrate Sass stylesheets from @import to @use and @forward
Replace deprecated Sass @import with the @use and @forward module system to stop namespace collisions and prepare for removal.
21 Feb 2026, 17:47 UTC

The problem: @import is deprecated and global by default
If your Sass project still uses @import, every variable, mixin, and function dumps into a single global namespace. In a small stylesheet that is manageable. In a design system with dozens of partials—Sass files prefixed with an underscore that are not compiled on their own—two files can accidentally define $color or @mixin reset, and the last import wins silently. Worse, the Sass team has deprecated @import and plans to remove it, so stylesheets that keep using it will eventually stop compiling.
The practical takeaway is to adopt the Sass module system: @use loads a module exactly once per compilation and namespaces its members (adds a prefix so names from different modules do not collide), while @forward re-exports selected members from one module to another. Dart Sass is the canonical implementation; LibSass and node-sass are deprecated and may not support @use fully.
How @use and @forward change the contract
@use does not copy styles into the current file. It loads the target module once, makes its public members available under a namespace, and prevents duplicate work. Members starting with an underscore or hyphen are private to that module.
@forward builds a single entry point. Instead of importing ten partials in every component file, components import one index module that forwards the pieces they need.
Ordering rules that break compiles
@usestatements must appear at the top of a stylesheet, before any non-plain-CSS rules.- Variable overrides using
!defaultmust be declared before the@usethat depends on them, or they are ignored. - Circular dependencies between modules are a compile-time error, not a silent fallback.
Worked example: a button module and design-system entry point
Assume this file structure under src/:
src/
_variables.scss
_buttons.scss
index.scss
main.scss
_variables.scss defines public design tokens with !default so downstream files can override them:
$brand-color: #0066cc !default;
$component-padding: 1rem !default;
_buttons.scss loads variables with @use and namespaces every reference:
@use 'variables';
@mixin button-base {
background-color: variables.$brand-color;
padding: variables.$component-padding;
border: none;
border-radius: 4px;
}
.button {
@include button-base;
}
index.scss forwards both modules so consumers have one import target:
@forward 'variables';
@forward 'buttons';
main.scss consumes the namespaced mixin and the forwarded variable:
@use 'src/buttons' as b;
@use 'src/index' as *;
.hero-button {
@include b.button-base;
color: $brand-color;
}
Run the compiler from the project root. You need read access to src/ and write access to the output directory:
sass --version
# Expected: Dart Sass 1.x, not node-sass or LibSass
npx sass src/main.scss dist/main.css
Risk: the command overwrites dist/main.css if it exists. Inspect the output to confirm namespaced CSS landed in the file and no Sass at-rules remain.
Limitations and practical verification
The module system is more verbose than @import. Every mixin or function needs its namespace prefix unless you load with as *, which re-introduces global access and defeats some encapsulation. You also cannot use @use mid-stylesheet after a rule; it must be at the top.
To verify a migration, search the source tree for remaining @import rules:
grep -R "@import" src/ --include="*.scss"
A successful migration returns no matches outside legacy files you plan to keep. Then compile a test file with Dart Sass and inspect the plain CSS output for expected class names and property values.
Closing: migrate one module at a time
Do not rewrite every stylesheet in one commit. Convert one leaf partial to @use, add an @forward entry point for that directory, compile, and check the CSS. Repeat until no @import remains. Keeping the change on a feature branch gives you a rollback path: revert the branch if compilation fails in CI.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.