QREATiv | Tutorial: Sass Feature-Freeze Thaws with a Migration to Modu


The Goal

Learn the basics of manually migrating your legacy Sass files to the new module system.

Specialties: Front-end dev; photorealistic hand-drawing
Years’ Experience: 22
Employer: Freelance
Tutorial Details
Difficulty Level: ★★
  • Basic / Inexperienced
  • ★★ Easy / Beginner
  • ★★★ Moderate / Experienced
  • ★★★★ Difficult / Expert
  • ★★★★★ Complex / Über Geek
Skills: Sass, coding
Tools: sass, dart, compiler
Completion Time: 30-45 minutes
Related Article: Source
Tags: sass, preprocessor, dart, migration

This is a member-contributed tutorial. If possible, contact the author with questions or comments.

The Sass Migration

A few things before we get started:

  • Sass is/was not dead/abandoned, it was just feature-frozen but it’s been officially back in active development since 2019.
  • Sass now uses a module system and comes with new features and a minor syntax update.
  • There’s more to learn about the module system which is beyond the scope of this tutorial.
  • Migration is not a one-time only process. According to Miriam Suzanne the official Sass migration tool will receive regular updates as new features are added. So regardless of tool more migrations are inevitable.

Speaking of Migration...

As to the last point above there are various migration tools available from Node, Chocolatey, Homebrew, and of course the official Sass version written by Jennifer Thakar. But depending on your comfort-level and/or understanding of such tools they might not be for everyone.

For those of you that use a GUI compiler app some of them might already have a built-in migration feature. If so, great, but if not keep reading. If you use the wonderful CodeKit (Mac) I believe developer Bryan Jones is aware of the new module system and syntax requirements though it remains to be seen if he will include a migration tool. That being said I wanted to get this initial migration moving a.s.a.p. so it’s the hands-on approach for me.

What to Expect

I wrote this intentionally very simple (manual) migration tutorial for those who don’t want to install command-line tools and just want the basics and nothing more. The bare minimum of @use and @forward outlined below should be sufficient to get most people up and running until you can do a deeper dive into the new system.


Now that Sass has made the jump to a module-based structure the way it handles partials internally has changed so we need to make some small but necessary syntax changes as it applies to @import. While the Sass dev team have made sure @import will continue to work alongside the new module-based approach it will eventually (perhaps in two years or so from the time of this writing) be dropped in favor of @use and @forward so don’t procrastinate.

Sass refers to mixins, variables, and functions as “members” which is how they are referred to in this tutorial.

Previously, in order to use members in other partials we could simply include their respective file(s) at the top of our partials listing in the root file, e.g. global.scss like so:

// The old syntax

// global.scss project root file w/ partial listing

@charset "UTF-8";

@import "mixins";  // All the members will be available to any files listed below that use mixins
@import "variables";  // All the members will be available to any files listed below that use variables
@import "main";
@import "form";
@import "menu";

Looks familiar, right?

Except now we need to use @use which is functionally very similar to @import (we’re still importing files) but is also slightly different and better. So using the above example our root file would now look like this:

// global.scss project root file w/ partial listing

@charset "UTF-8";

@use "main";
@use "form";
@use "menu";

Notice the mixins and variables files are missing.

With the new system when a partial, e.g. _main.scss, needs access to the members of another file, e.g. _mixins.scss, we need to explicitly call said file(s) with @use from the partial, not the root global.scss file. It’s a simple matter of calling the required file at the very top of the partial, before anything else.

Only @charset and simple variable definitions can appear before the import commands.

// At the top of _main.scss

@charset "UTF-8";

@use "mixins" as *;  // All the members of this file will be available to _main.scss

/* !Begin Main Styles */

* {
	@include hyphens;

If you need to make available additional member files, e.g., variables, then simply add them one after another in the order you need to load them like so:

/* At the top of _main.scss */

@charset "UTF-8";

@use "mixins" as *;  // All the members of this file will be available to _main.scss
@use "variables" as *;  // All the members of this file will be available to _main.scss

/* !Begin Main Styles */

* {
	@include hyphens;

Using the example above, if either the _form.scss or _menu.scss partials also required member access then they too would need @use "mixins" as *; or @use "variables" as *; at the top of their respective files, just like we did with the _main.scss partial.

You’ll notice that as * has been appended to the call. What this does is make available all members of the included partials for use in _main.scss. Without as * the Dart compiler would throw errors about any undefined mixins, variables, or functions used in _main.scss.

For example, @include hyphens; as shown above would throw the following error if as * were missing.

Dart Sass failed with this error: Error: Undefined mixin.
7 ?     @include hyphens;
  ?     ^^^^^^^^^^^^^^^^
  _main.scss 7:2   @use
  global.scss 4:1  root stylesheet

It’s also possible to target a specific member instead of loading everything when you know for certain a particular partial only has need of one (or a few) members. In such cases the use of as * is not required. Check the Sass docs for the specific syntax.

So instead of the blanket coverage we enjoyed under the previous method we now need to explicitly add any required files on a partial-by-partial basis. Not a big deal but a bit more more work for more granular control.


This is pretty handy.

As always you are free to organize your partials however you like. What @forward does is allow you to group similar partials under one namespace e.g., ui, for use in another file. Or you can cherry pick only the partials you need with a separate call for each file. Either way works.

So, after grouping the partials under a folder, e.g., ui we need to create an _index.scss file. This acts as the root file for the ui namespace so we can @forward all the partials (or individual ones) contained within the ui folder.

// ui/index.scss partial listing

@forward "menu";
@forward "slider";
@forward "tipped";

Then @use them as normal. This will load all 3 files as defined in ui/index.scss.

// main.scss

@use "mixins" as *;
@use "ui" as *;

/* !Begin Main Styles */

* {
	@include hyphens;

As mentioned, if you only want to use one file from the ui folder/namespace, e.g., _menu.scss, instead of all three then call it as normal but remember to adjust the path accordingly.

// main.scss

@use "ui/menu" as *; // Include only the "menu" partial from the parent folder "ui". The remaining two files will not be included.

/* !Begin Main Styles */

* {
	@include hyphens;

Keep in mind that if _menu.scss requires any additional members like mixins (spoiler: it does) then be sure to call those files too or you’ll get errors.

// At the top of _menu.scss

@use "mixins" as *;

/* !Begin Menu Styles */


Wrap Up

There’s still plenty of time to migrate, probably two years. Thankfully the Sass team has put the time and effort into ensuring @import continues to work in parallel with the new system right up to the day it gets dropped.

Tutorials Archive show by year/month