The basics
What is an SCSS file?
An SCSS file is the source code of a stylesheet written in Sass, a language that extends CSS. It adds what plain CSS long lacked: variables, nesting, reusable blocks called mixins, functions, loops and a module system for splitting styles across files. Browsers can't read it. A compiler, usually Dart Sass, turns it into a normal .css file, and that is what a web page loads.
Sass has two syntaxes. SCSS (.scss) uses braces and semicolons like CSS, and almost any valid CSS file is also valid SCSS, so you can rename style.css to style.scss and start adding features. The older indented syntax (.sass) drops the braces and semicolons and uses indentation instead. Both compile to the same CSS, and a project can mix them. SCSS is by far the more common one.
You meet SCSS files in front-end projects: theme files for frameworks such as Bootstrap (written in Sass since version 4), component styles in Angular, Vue and React projects, and design-system packages that ship their tokens as Sass variables.
- Not CSS. A browser given an
.scssfile ignores it. Only the compiled.cssfile styles a page. - Not a framework. Sass is a language. Bootstrap or a design system may be written in it, but Sass itself has no ready-made styles.
- Not Node Sass.
node-sasswas a wrapper around LibSass, an older compiler that is no longer maintained. Today's compiler is Dart Sass, installed from npm assass.
Anatomy
What's inside an SCSS file
SCSS looks like CSS with extra powers: anything you can write in a .css file works, and on top of that come variables, nesting, mixins, functions and modules. Here is a small partial, part by part. It assumes a _tokens.scss file next to it that defines $brand.
// _buttons.scss: button styles
@use "sass:color";
@use "tokens" as t;
$padding: 0.5rem 1rem !default;
@mixin focus-ring($c: t.$brand) {
outline: 3px solid $c;
}
/* Buttons */
.button {
padding: $padding;
background: t.$brand;
&:hover {
background: color.scale(t.$brand, $lightness: -15%);
}
&--large {
font-size: 1.25rem;
}
&:focus-visible {
@include focus-ring;
}
}- 1
// _buttons.scss: button stylesA silent comment
Comments with
//are for the people editing the file and never reach the CSS. The leading underscore in the file name makes this a partial: Sass won't compile it on its own, only as part of a file that loads it. - 2
@use "sass:color";A built-in module
Sass's own functions come in modules such as
sass:color,sass:mathandsass:map. After this line, colour functions are called ascolor.scale(),color.adjust()and so on. - 3
@use "tokens" as t;Loading another file
Loads
_tokens.scssfrom the same folder, once, under the namespacet. You leave out the underscore and the extension.@userules must come before any style rules. - 4
$padding: 0.5rem 1rem !default;A variable
Sass variables start with
$.!defaultmeans "use this unless the file loading me set it already", which is how libraries let you configure them. - 5
@mixin focus-ring($c: t.$brand) { … }A mixin
A reusable block of declarations with an optional parameter and a default value. It produces nothing until it's included somewhere.
- 6
/* Buttons */A loud comment
A normal CSS comment. Sass copies it into the output, except in compressed mode. Start it with
/*!to keep it even then, for licence notices. - 7
t.$brandA member of another module
The variable
$brandfrom_tokens.scss, reached through its namespace. With@use, nothing becomes global, so you always know where a name comes from. - 8
&:hover { … }Nesting and the parent selector
A rule inside a rule.
&stands for the outer selector, so this compiles to.button:hover. - 9
color.scale(t.$brand, $lightness: -15%)A function call
Runs while compiling and outputs a plain colour. The browser never sees the function, only the result.
- 10
&--large { … }Building a class name
&--largebecomes.button--large, the BEM naming style. This is one thing native CSS nesting can't do: there,&can't be glued to the rest of a class name. - 11
@include focus-ring;Using the mixin
Copies the mixin's declarations here, with the default parameter.
How it's used
How an SCSS file becomes CSS
Compiling means running the file through Sass, which works out every variable, mixin, loop and function and writes plain CSS. The small partial above compiles to this:
/* Buttons */
.button {
padding: 0.5rem 1rem;
background: #046eff;
}
.button:hover {
background: rgb(0%, 36.4594953519%, 86.3333333333%);
}
.button--large {
font-size: 1.25rem;
}
.button:focus-visible {
outline: 3px solid #046eff;
}Two things to notice: the // comment and the mixin are gone, and the darker colour is written out in full. Dart Sass 1.106 keeps the exact channel values of computed colours, and writes them as percentages in rgb() when they aren't whole numbers.
| Where | Install or run | Notes |
|---|---|---|
| Any OS with Node.js | npx sass in.scss out.css, or npm install -g sass | The pure JavaScript build; the sass-embedded package is faster |
| macOS or Linux | brew install sass/sass/sass | Installs the native Dart Sass |
| Windows | choco install sass | Or download the standalone ZIP from the Dart Sass releases on GitHub |
| In a project | Vite, webpack (sass-loader), Angular CLI, Next.js | These compile .scss files for you; most need the sass package installed in the project |
- Watch mode:
sass --watch src/styles.scss dist/styles.cssrecompiles on every save. - A whole folder:
sass src/scss:dist/csscompiles every file except partials. - Minified output: add
--style=compressed. Loud comments disappear unless they start with/*!. - Source maps: Dart Sass writes a
.css.mapfile next to the CSS by default, so browser developer tools can show the SCSS line each rule came from. Add--no-source-mapto skip it.
Versions
@use, @forward and the end of @import
For most of Sass's life, files were combined with @import. It made every variable, mixin and function global, so in a large project nobody could tell where a name came from, and a file imported twice was compiled twice. The module system replaced it: @use loads a file once, under a namespace, and @forward passes a file's members on to whoever loads the current one.
| When | What changed |
|---|---|
| Dart Sass 1.23.0 (October 2019) | @use, @forward and built-in modules such as sass:math arrive. |
| October 2020 | LibSass, and with it Node Sass, is deprecated. Neither ever supported @use. LibSass reached end of life in October 2025. |
| Dart Sass 1.80.0 (October 2024) | @import is deprecated, and so are global built-in functions such as darken() when a module version exists. Both print warnings. |
| Dart Sass 2.0.0 (not yet released) | Planned to remove / as division; use math.div() or calc(). The Sass team says 2.0.0 won't change @import. |
| Dart Sass 3.0.0 (not yet released) | Planned to remove @import and the global built-in functions. As of October 2026 the current release is 1.106.1, so both still work, with warnings. |
// styles/_index.scss: one entry point for a folder of partials
@forward "tokens";
@forward "mixins";
// main.scss
@use "styles"; // loads styles/_index.scss
.card { color: styles.$brand; }A folder can have an _index.scss file that loads in place of the folder, as above. Imports of plain CSS are left alone: @import "theme.css"; or @import url(…) passes through to the output as a normal CSS @import.
Migrating old files
The official migrator rewrites @import to @use and adds namespaces: npx sass-migrator module --migrate-deps main.scss. Its division command turns / into math.div() or a multiplication. Commit first, and check the result: some projects relied on everything being global.
File conventions
Partials, encoding and comments
- Partials: a file named
_name.scssis only loaded by other files. Folder compiles skip it, and you load it as@use "name", without the underscore. A typical project has one or a few entry files such asmain.scss, and many partials. - Loading order:
@useand@forwardrules must come before other rules. Variable declarations may go above them, which is how@use … with (…)configuration works. - Encoding: save files as UTF-8. When the output contains non-ASCII characters, Dart Sass adds
@charset "UTF-8";to expanded CSS, or a byte order mark to compressed CSS, so browsers decode it correctly. Escapes such as"\20AC"come out as the character itself (€). - Line endings and BOM: Dart Sass accepts CRLF line endings and a UTF-8 byte order mark at the start of a file;
sample-windows.scsshas both. - Comments:
//comments vanish;/* */comments are copied into expanded CSS;/*! */comments survive even compressed output.///comments are documentation comments that SassDoc can turn into reference pages. - Private members: a variable, mixin or function whose name starts with
-or_is private to its file and can't be used through@use.
Comparison
SCSS vs Less vs plain CSS
Plain CSS has gained several features that were once reasons to use a preprocessor. It still lacks others, which is why Sass remains common.
| SCSS (Sass) | [Less](/file-types/less) | Plain [CSS](/file-types/css) | |
|---|---|---|---|
| Needs compiling | Yes | Yes (or less.js in the browser) | No |
| Variables | $name, fixed when compiled | @name, fixed when compiled, lazily evaluated | Custom properties --name, live in the browser (all major browsers since 2017) |
| Nesting | Yes, including &-suffix | Yes, including &-suffix | Yes, in all major browsers since 2023, but & can't build class names |
| Mixins | @mixin / @include | Any class or .name() rule | No |
| Logic and loops | @if, @each, @for, @while, @function | Guards (when), recursion, each() | Conditions only through @media, @supports and @container |
| Splitting into files | @use / @forward, merged into one CSS file | @import, merged into one CSS file | @import makes the browser fetch each file |
| Comments | // and /* */ | // and /* */ | /* */ only |
| Main tool | Dart Sass | less.js (lessc) | The browser |
Sass variables and CSS custom properties work well together: Sass values disappear when the file is compiled, while custom properties can change at run time, for a dark theme, say. The featured sample writes Sass values into custom properties with --brand: #{$brand};.
Troubleshooting
Why won't my SCSS compile?
| Message | Usual cause | Fix |
|---|---|---|
Can't find stylesheet to import. | Wrong path, or a package in node_modules that Sass doesn't look in | Check the path relative to the file. For packages, pass --load-path=node_modules or set your build tool's load paths |
Undefined variable. | With @use, members of another file need its namespace, such as t.$brand | Add the namespace, or @use "tokens" as * to drop it |
@use rules must be written before any other rules. | A style rule or @include sits above an @use | Move all @use and @forward lines to the top |
expected "}". or expected end of rule. | A missing brace or semicolon | The error shows the line; the real mistake is often just above it |
DEPRECATION WARNING [import] or [global-builtin] | @import, or functions such as darken(), which Dart Sass 3.0.0 will remove | Run sass-migrator module, or switch to @use and color.adjust() by hand |
DEPRECATION WARNING [slash-div] | $a / 2 used as division | Write math.div($a, 2) or calc($a / 2) |
Node Sass does not yet support your current environment | An old project uses node-sass, a native module built for older Node.js versions | Replace node-sass with sass in package.json; most code compiles unchanged |
When CSS comes out but looks wrong, open the browser's developer tools: with source maps on, each rule links back to the SCSS line it came from.
How to
How to open, edit and convert an SCSS file
- Open or edit it: any plain-text editor works. VS Code highlights and checks SCSS without extensions; JetBrains IDEs do too. On a phone, a text or code viewer app shows it.
- Turn it into CSS: compile it, as above. To try a snippet without installing anything, paste it into the Sass Playground on sass-lang.com.
- Turn CSS into SCSS: rename the file. Almost any valid CSS is valid SCSS, so you can then add variables and nesting gradually.
- Use it on a website: compile it and link the
.cssfile with<link rel="stylesheet">. Linking the.scssfile directly does nothing. - Format and lint it: Prettier formats
.scssfiles, and Stylelint with an SCSS config checks them for mistakes and style.
Security
What SCSS can reveal, and compiling other people's Sass
An SCSS file can't run in a browser, so opening one is harmless. Two things are worth checking before files go online:
- Source maps expose your source. A
.css.mapnext to public CSS points to, and can embed, the original SCSS, including//comments that never reached the CSS. That's fine for open projects; for others, don't deploy the maps, or keep comments free of internal notes, hostnames and ticket links. - Sass is a programming language. A service that compiles Sass from users runs their loops and loads the files they ask for from its load paths. Compile untrusted input with time and memory limits, and with load paths that contain nothing private.
Free downloads
Sample SCSS files to download
Free sample Sass files for testing compilers, build pipelines, editors and syntax highlighters. Every file compiles without errors or warnings in Dart Sass 1.106.1.
Loading…What's inside sample-styles.scss
The file is commented: open it in a text editor and each numbered comment marks one of these parts. sample-styles.css is what Dart Sass makes of it.
Comment 1: built-in modules
@useloadssass:color,sass:mapandsass:math, so the rest of the file callscolor.scale(),map.get()andmath.div().Comments 2 to 4: variables, a map and a function
$brandand$radiuswith!default, a map of breakpoints, and arem()function that converts pixels to rem withmath.div().Comments 5 and 6: a mixin and a placeholder
above("md")wraps its content in a media query and stops the compile with@errorfor an unknown breakpoint.%focus-ringonly appears in the CSS because.button:focus-visibleextends it, at the placeholder's position, which is why that rule comes first in the output.Comment 7: Sass variables into custom properties
--brand: #{$brand};writes a compile-time value into a CSS variable that stays live in the browser.Comments 8 and 9: nesting and colour functions
A
.cardwith nestedh2,&:hover,&--featuredand a media query that bubbles up, and a.buttonwhose hover colour is computed withcolor.scale().Comments 10 and 11: loops
@eachturns a map into three.badge-*classes, and@forwrites.mt-1to.mt-4.Comment 12: non-ASCII output
A
€in acontentstring makes Dart Sass start the CSS with@charset "UTF-8";.
All sample SCSS files
Commented SCSS stylesheet
sample-styles.scss · 2.9 KB (2,994 bytes)
A self-contained stylesheet that uses built-in modules, variables, a map, a function, a mixin with
@content, a placeholder with@extend, nesting,@eachand@for, with 12 numbered comments.- Testing Sass compilers and build pipelines
- Teaching the parts of an SCSS file
Compiled CSS of the featured sample
sample-styles.css · 1.2 KB (1,258 bytes)
The output of
npx sass --no-source-map sample-styles.scss sample-styles.csswith Dart Sass 1.106.1. It passes the CSSTree validator.- Comparing your compiler's output
- Seeing what each Sass feature turns into
Partial with variables, a function and a mixin
_sample-tokens.scss · 770 bytes
A partial (leading underscore) with
!defaultvariables, a private$-ratioand a function and mixin for other files to use. Download it together withsample-main.scss.- Testing that tools skip partials
- Testing `@use … with (…)` configuration
Entry file that loads the partial with @use
sample-main.scss · 957 bytes
Loads
_sample-tokens.scsswith@use "sample-tokens" as tokens with (…), overriding two defaults, and uses its members through the namespace. Put both files in the same folder to compile it.- Testing module resolution and load paths
- Checking a migration from `@import` to `@use`
Indented syntax (.sass)
sample-indented.sass · 849 bytes
The same kinds of rules in Sass's original syntax: no braces or semicolons, with indentation for nesting and a mixin with a parameter.
- Testing `.sass` support in compilers and editors
- Comparing the two Sass syntaxes
UTF-8 with BOM and CRLF line endings
sample-windows.scss · 800 bytes
Saved with a UTF-8 byte order mark and Windows line endings, with text in eight scripts, emoji, a
.caféclass and a\20ACescape.- Checking tools that choke on a BOM or CRLF
- Spotting encoding bugs in the CSS output
Ways to test with them
- Compiler output: compile
sample-styles.scsswith your setup and compare it withsample-styles.css. Older compilers differ in colour formatting; LibSass rejects@usealtogether. - Partials and load paths: compile the folder with
sass .:out._sample-tokens.scssshould be skipped, andsample-main.scssshould find it. - Encoding: compile
sample-windows.scss. The CSS should start with@charset "UTF-8";and show the text unchanged; anyÃorâ€means a step misread UTF-8. - Syntax support: an editor or highlighter that handles
.scssbut not.sasswill showsample-indented.sassas plain text.
Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.
Put it online
Have an SCSS file? Give it a link.
Drop an SCSS file on 99helpers and it gets its own address, handy for sharing a theme file or a snippet for review. Opened in a browser, the link shows the source as plain text: browsers can't apply SCSS, so to style a page, compile it and host the .css file.
Questions
SCSS files, frequently asked
What is the difference between SCSS and Sass?
Sass is the language; SCSS is its main syntax, with braces and semicolons like CSS, in .scss files. The older indented syntax, in .sass files, uses indentation instead. Both compile to the same CSS.
How do I open an SCSS file?
With any text editor, such as VS Code, Notepad or TextEdit in plain-text mode. It's source code, so there's nothing to view until you compile it to CSS.
How do I convert SCSS to CSS?
Compile it with Dart Sass: npx sass input.scss output.css if you have Node.js, or install Sass with Homebrew or Chocolatey. Build tools such as Vite do it automatically once the sass package is installed.
Can browsers read SCSS?
No. Browsers only apply CSS. Linking an .scss file in a page has no effect; link the compiled .css file instead.
Is @import deprecated in Sass?
Yes, since Dart Sass 1.80.0 in October 2024, and it's due to be removed in Dart Sass 3.0.0, which isn't out yet. Use @use and @forward; sass-migrator module converts old files.
What does the underscore in _file.scss mean?
It marks a partial: a file meant to be loaded by other files, not compiled on its own. Load it without the underscore, as @use "file".
Do I still need Sass now that CSS has variables and nesting?
Less than before. Custom properties and native nesting cover many basic uses. Sass still adds mixins, functions, loops, modules and compile-time maths, and a compile step that merges files into one.
Should I use node-sass or sass?
sass, which is Dart Sass. node-sass is built on LibSass, which is no longer maintained and never supported @use.
Related formats
Other file types explained
Keep going
Related
Sources
- Sass documentation: syntax (SCSS and indented)
- Sass documentation: @import, partials and index files
- Sass blog: @import is deprecated
- Sass documentation: comments
- Install Sass
- Sass blog: LibSass has reached end of life
Last reviewed 27 October 2026.