Implementing the Sass Module System with @use and @forward
Stop using @import in Sass. Learn how to use @use and @forward to implement namespacing, prevent global variable collisions, and build maintainable design systems.
30 Jan 2026, 02:56 UTC

Solving Global Namespace Collisions
The legacy Sass @import rule is deprecated because it treats every imported file as a global addition to the stylesheet. This creates "namespace pollution," where a variable named $primary-color in one file can silently overwrite the same variable in another, making debugging large projects difficult.
The solution is the Sass Module System, specifically the @use and @forward rules. These ensure that each file is loaded as an isolated module, and its members (variables, mixins, and functions) are accessed via a namespace, preventing accidental overrides and improving compilation performance by loading each file exactly once.
Managing Dependencies with @use
The @use rule loads a stylesheet and assigns it a namespace based on the filename. To use a member from that module, you prefix it with the namespace.
// _colors.scss
$primary: #007bff;
$secondary: #6c757d;
// main.scss
@use 'colors';
.button {
background-color: colors.$primary;
}
If a filename is cumbersome, you can define a custom alias using as:
@use 'brand-style-guide' as brand;
.header {
color: brand.$primary;
}
Configuring Modules via !default
You can customize a module's internal variables during the load process using the with clause. This only works for variables declared with the !default flag, which tells Sass to use the provided value only if one hasn't already been assigned.
// _library.scss
$base-padding: 10px !default;
$border-radius: 4px !default;
// main.scss
@use 'library' with (
$base-padding: 20px
);
.card {
padding: library.$base-padding; // Resolves to 20px
}
Architecting Libraries with @forward
When building a design system, you often have many small partials but want to provide a single entry point for the consumer. The @forward rule allows you to gather multiple modules and re-export them as a single package.
// _index.scss (The entry point)
@forward 'buttons';
@forward 'forms';
@forward 'typography' as type-*;
// app.scss
@use 'index';
.element {
@include index.button-style;
font-family: index.type-main-font;
}
The as type-* syntax adds a prefix to all members of the forwarded module, which is critical for avoiding collisions when forwarding multiple files that might use similar naming conventions.
Built-in Sass Modules
Modern Sass has moved global functions into built-in modules. You must load these explicitly to perform mathematical operations or color manipulations.
@use 'sass:math';
.grid-item {
// Replaces the deprecated / operator for division
width: math.div(100%, 3);
}
Constraints and Common Pitfalls
- Top-Level Requirement:
@useand@forwardmust be declared at the top of the file. They cannot be nested inside CSS rules, mixins, or functions. - Single Configuration: A module can only be configured with
with (...)the first time it is loaded in a compilation. Subsequent@usecalls to the same module must not include a configuration block, or the compiler will throw an error. - Compiler Support: These features are exclusive to Dart Sass. LibSass and Ruby Sass are deprecated and do not support the module system.
- Partials: Ensure files intended as modules start with an underscore (e.g.,
_colors.scss) to prevent the compiler from generating standalone CSS files for them.
Verification Steps
To verify your implementation, run sass --version to ensure you are using Dart Sass. Compile a file using math.div(); if the output CSS contains the calculated value and no deprecation warnings appear in the terminal, the module system is functioning correctly. To test configuration locking, attempt to @use the same module twice in different files with different with blocks; the compiler should report a configuration error.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.