Compilation

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.

Browsers do not understand Sass. No browser has ever shipped support for $variables, @mixin, @use, or the indented syntax, and none is planning to. Sass is a build-time language: a compiler reads your .scss/ .sass sources and emits plain .css that any browser can parse. Everything documented in this section — variables, nesting, mixins, functions, control flow, modules — exists only in the source and is gone by the time the stylesheet is served.

This is the fundamental difference between a Sass variable and a CSS custom property (see Variables): one is erased at compile time, the other is shipped and live in the browser.

The pipeline

flowchart LR subgraph entry["Entry points"] CLI["sass CLI
sass src:dist --watch"] BUNDLER["Bundler
Vite / Webpack sass-loader"] EDITOR["Editor extension
compile on save"] end SRC[".scss / .sass sources
+ partials"] COMPILER["Dart Sass compiler"] CSS["plain .css output"] MAP["source map (.css.map)"] BROWSER["Browser"] SRC --> CLI SRC --> BUNDLER SRC --> EDITOR CLI --> COMPILER BUNDLER --> COMPILER EDITOR --> COMPILER COMPILER --> CSS COMPILER -.-> MAP CSS --> BROWSER MAP -.debugging.-> BROWSER classDef core fill:#3f51b5,stroke:#1a237e,color:#fff class COMPILER core

All three entry points drive the same compiler. Choosing between them is a workflow decision, not a capability one — the CSS produced is identical.

Implementations

Implementation Status Notes

Dart Sass

Current, official

The reference implementation. Written in Dart, distributed as a standalone executable, as a pure-JS sass npm package, and as sass-embedded (a fast native binary with a JS wrapper). All new features land here first.

LibSass (node-sass)

Deprecated

The C++ implementation. Officially deprecated in 2020 and no longer maintained. It never gained the module system (@use/@forward) and never will. node-sass was its Node binding and is likewise end-of-life.

Ruby Sass

End of life

The original implementation. Retired in 2019.

The practical consequence: if a project still depends on node-sass, migrate it to sass. Beyond being unmaintained, node-sass requires native compilation tied to specific Node versions, which is a recurring source of install failures. The replacement is usually a one-line change:

npm uninstall node-sass
npm install --save-dev sass

For build-performance-sensitive projects, sass-embedded offers the same API backed by a native binary:

npm install --save-dev sass-embedded

The sass CLI

The most direct path. Install it globally or as a dev dependency:

npm install -g sass          # or: brew install sass/sass/sass

Basic invocations:

# One file
sass scss/main.scss css/main.css

# A whole directory (partials are skipped automatically)
sass scss:css

# Recompile on every save
sass --watch scss:css

# Production build: compressed, no source map
sass scss:css --style=compressed --no-source-map

Useful flags

Flag Effect

--watch

Recompile whenever a source file changes

--style=expanded / --style=compressed

Output formatting; expanded is the default, compressed minifies

--no-source-map

Skip the .css.map file (do this for production)

--load-path=<dir>

Extra directory to resolve @use/@forward from — e.g. node_modules

--embed-sources

Inline the original Sass into the source map

--error-css / --no-error-css

Whether to emit CSS describing an error, so it shows up in the browser

--quiet-deps

Suppress deprecation warnings originating in dependencies

--update

Only recompile files whose sources changed

--load-path=node_modules is the one people most often need, since it lets @use "bootstrap/scss/bootstrap" resolve without a relative path full of ../.

Output styles

.button { background: #3f51b5; color: white; }

--style=expanded (default) — readable, one declaration per line:

.button {
  background: #3f51b5;
  color: white;
}

--style=compressed — minified, whitespace stripped, for production:

.button{background:#3f51b5;color:white}

Dart Sass dropped the older nested and compact styles; expanded and compressed are the two that remain.

Source maps

By default the compiler writes a .css.map alongside the CSS. Browser developer tools read it and report the original .scss file and line number for each rule, instead of a line in the generated CSS. Without one, debugging a large compiled stylesheet means tracing rules back by hand.

Ship source maps in development; drop them in production builds (--no-source-map) unless you deliberately want them available.

Bundler integrations

Vite

Vite supports Sass out of the box — no plugin or config needed. Install the compiler and import the file:

npm install --save-dev sass
// main.js
import './styles/main.scss';

.module.scss files are treated as CSS Modules automatically. Shared variables can be injected into every stylesheet via config:

// vite.config.js
export default {
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "src/styles/_tokens.scss" as tokens;`
      }
    }
  }
};

Webpack

Webpack needs an explicit loader chain, applied right-to-left:

npm install --save-dev sass sass-loader css-loader style-loader
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          'style-loader',   // 3. inject the CSS into the DOM
          'css-loader',     // 2. resolve @import/url() in the CSS
          'sass-loader'     // 1. compile Sass → CSS
        ]
      }
    ]
  }
};

For production, replace style-loader with MiniCssExtractPlugin.loader to emit a real .css file rather than injecting styles via JavaScript.

Pin sass-loader to the Dart Sass implementation explicitly if the project has any node-sass history:

{
  loader: 'sass-loader',
  options: {
    implementation: require('sass'),
    sassOptions: { loadPaths: ['node_modules'] }
  }
}

Other tooling

  • Parcel — zero-config, like Vite; install sass and import the file.

  • npm scripts — for a project with no bundler, the CLI is enough:

    {
      "scripts": {
        "css:build": "sass scss:dist/css --style=compressed --no-source-map",
        "css:watch": "sass --watch scss:dist/css"
      }
    }
  • Framework CLIs — Angular, Next.js, Nuxt, and SvelteKit all support Sass by installing the sass package; none needs further configuration in the common case.

Editor compile-on-save

For small projects or quick experiments, an editor extension avoids any build setup at all. Live Sass Compiler for VS Code is the widely used one: it watches open .scss files and writes the compiled CSS on save, with configurable output path and style.

This is convenient for learning and for single-page sites, but it is not a substitute for a real build step on a team project — the configuration lives in one developer’s editor settings rather than in the repository, so different machines can silently produce different output.

Where compilation fits in the wider pipeline

Sass compilation is normally one stage among several:

  1. Sass → CSS (Dart Sass, covered here).

  2. Autoprefixer / PostCSS — add vendor prefixes and apply other CSS transforms.

  3. Minification — either Sass’s own --style=compressed, or a dedicated minifier such as cssnano.

  4. Bundling and cache-busting — emit a hashed filename for long-lived caching.

Sass deliberately does not do vendor prefixing itself; that is Autoprefixer’s job, driven by a browserslist configuration.

For the CSS-side concerns that follow compilation — critical CSS, loading strategy, and bundle size — see Runtime loading performance and Build-time performance optimization.