Partials and Modules (@use / @forward)
|
This section documents Sass/SCSS as implemented by Dart Sass, the current official and actively maintained compiler — it is not tied to any specific book, build tool, or CSS framework (Bootstrap, Bulma, etc.). Unlike the other reference sections on this site, no single reference book underpins it: the content was generated with the assistance of AI from general knowledge of Dart Sass, and should be verified against the current official documentation at sass-lang.com before relying on it in production. Sass continues to evolve, so behaviour described here may lag the compiler you are actually running. This section’s bibliography lists the reference material consulted while preparing these pages. |
Splitting a stylesheet across many files is what makes a large Sass codebase manageable. Sass’s module system — @use and @forward — controls how those files load each other, what names they expose, and how they are
configured. It replaces the older @import rule, which is deprecated.
Partials
A partial is a Sass file whose name begins with an underscore: _variables.scss, _buttons.scss. The
underscore tells the compiler "this file is not a stylesheet in its own right — do not compile it to a
standalone .css file". It exists only to be loaded by other files.
scss/
├── main.scss ← compiled to main.css
├── _variables.scss ← partial, not compiled on its own
├── _mixins.scss ← partial
└── components/
├── _button.scss
└── _card.scss
When loading a partial, the leading underscore and the file extension are both omitted:
@use "variables"; // loads _variables.scss
@use "components/button"; // loads components/_button.scss
Without the underscore, running sass scss/:css/ would emit a variables.css, mixins.css, and so on
alongside the one file you actually wanted — which is the entire reason the convention exists.
@use
@use loads another stylesheet as a module, making its variables, mixins, and functions available.
// _colors.scss
$primary: #3f51b5;
$danger: #e53935;
@mixin text-on-primary { color: white; }
// main.scss
@use "colors";
.button {
background: colors.$primary;
@include colors.text-on-primary;
}
Three properties of @use matter, and all three are improvements over @import:
-
Members are namespaced. By default the namespace is the file’s basename without underscore or extension (
colors), and members are reached ascolors.$primary. Nothing leaks into the global namespace, so two modules can both define$primarywithout colliding. -
Each module is loaded exactly once, no matter how many files
@useit.@importre-evaluated the file every time, duplicating its CSS output. -
@usemust appear at the top of the file, before any rules other than@charsetand other@use/@forwardlines. This makes the dependency graph statically analysable.
Choosing a namespace with as
@use "components/button" as btn; // btn.$height
@use "very/long/path/typography" as t;
Loading without a namespace: as *
as * drops the namespace and dumps the module’s members into the current scope:
@use "colors" as *;
.button { background: $primary; } // no prefix needed
Convenient, but it reintroduces exactly the collision risk namespaces were designed to prevent. Reserve it for a single project-wide token file, and prefer explicit namespaces everywhere else.
Private members
A member whose name starts with - or _ is private to its module: usable inside the file that defines it,
invisible to anything that `@use`s it.
// _colors.scss
@use "sass:color";
$-internal-seed: #123456; // private
$primary: color.adjust($-internal-seed, $lightness: 40%); // fine here
Configuring a module with with
A module’s !default variables (see Variables) are its configuration surface. A
loader overrides them at load time with with:
// _theme.scss
$primary: #3f51b5 !default;
$radius: 4px !default;
$font: sans-serif !default;
.button {
background: $primary;
border-radius: $radius;
font-family: $font;
}
// main.scss
@use "theme" with (
$primary: #e91e63,
$radius: 12px
);
Constraints worth remembering:
-
Only variables declared with
!defaultcan be configured; anything else is an error. -
A module can be configured only once, and only by the first file that loads it. If two files both write
@use "theme" with (…), compilation fails. -
Configuration is applied before the module’s own body runs, so the module’s rules see the new values.
@forward
@forward makes another module’s members visible to files that load this one, without using them here. It is
how a library exposes a single entry point that aggregates many internal partials.
// _index.scss -- the public face of the library
@forward "colors";
@forward "typography";
@forward "spacing";
// main.scss
@use "theme"; // loads theme/_index.scss
.button {
background: theme.$primary; // defined in theme/_colors.scss
font-family: theme.$font-stack; // defined in theme/_typography.scss
}
A directory containing an _index.scss (or _index.sass) can be loaded by directory name alone — @use
"theme" finds theme/_index.scss automatically.
@forward does not make the members usable in the forwarding file itself. To both re-export and use them,
write both rules — Sass loads the module only once regardless:
@forward "colors";
@use "colors";
.debug { outline: 1px solid colors.$danger; }
show and hide
@forward "colors" show $primary, $danger, text-on-primary; // only these
@forward "internals" hide $-scratch, reset-everything; // all but these
show is the safer default for a public library API: it makes the exposed surface explicit, so adding a member
internally does not silently widen the API.
Prefixing with as
@forward "…" as prefix-* prepends a prefix to every forwarded member’s name — useful for keeping an
aggregated namespace readable while still exposing everything through one entry point:
// _index.scss
@forward "colors" as color-*;
@forward "typography" as type-*;
@use "theme";
.button {
background: theme.$color-primary; // was $primary in _colors.scss
font-family: theme.$type-font-stack; // was $font-stack in _typography.scss
}
A forwarded module’s configuration can also be set or re-exposed: @forward "theme" with ($primary: red
!default) forwards theme while supplying a new default that the eventual consumer may still override.
A worked module graph
Putting it together — an entry stylesheet that `@use`s two component partials, one of which `@forward`s a shared token partial:
(compiled → main.css)"] IDX["theme/_index.scss"] COL["theme/_colors.scss"] TYP["theme/_typography.scss"] BTN["components/_button.scss"] MAIN -- "@use 'theme'" --> IDX MAIN -- "@use 'components/button'" --> BTN IDX -- "@forward 'colors'" --> COL IDX -- "@forward 'typography'" --> TYP BTN -- "@use '../theme'" --> IDX classDef entry fill:#3f51b5,stroke:#1a237e,color:#fff classDef agg fill:#7986cb,stroke:#3f51b5,color:#fff class MAIN entry class IDX agg
theme/_index.scss is loaded by both main.scss and components/_button.scss, but it is evaluated exactly
once, and theme/_colors.scss reaches main.scss only through the @forward chain.
@import is deprecated
Sass’s original @import rule is deprecated and slated for removal from Dart Sass. Prefer @use/@forward in
all new code.
@import (deprecated) |
@use / @forward |
|---|---|
Everything is global — collisions are silent and order-dependent |
Members are namespaced per module |
The same file loaded twice is evaluated twice, duplicating CSS |
Each module is evaluated exactly once |
Can appear anywhere, including nested in a rule |
Must appear at the top of the file |
No notion of private members |
|
Configured only by assigning globals before importing |
Configured explicitly with |
// old
@import "variables";
@import "mixins";
.button { background: $primary; @include button-base; }
// new
@use "variables" as v;
@use "mixins" as m;
.button { background: v.$primary; @include m.button-base; }
Note that CSS also has its own @import, which is unrelated and not deprecated. Sass passes a plain CSS
@import through untouched when the URL is absolute, ends in .css, or is written as url(…) — so
@import url("https://fonts.googleapis.com/…") still works as expected.
The official sass-migrator tool automates the conversion:
npm install -g sass-migrator
sass-migrator module --migrate-deps scss/main.scss