Sass @import Rule

Beginner
⏱️ 14 min read
📚 Updated: Jul 2026
🎯 5 Examples
Deprecated

What You’ll Learn

Sass @import extends CSS’s @import to load Sass/CSS files at compile time. It is deprecated—this tutorial explains how it worked, why it causes problems, how it differs from @use, and how to migrate, with five compiled examples.

01

Status

Deprecated

02

Behavior

Global members

03

Nesting

Scoped CSS

04

Plain CSS

Passthrough

05

Migrate

@use / @forward

06

Practice

5 examples

What Is Sass @import?

Official docs: Sass extends CSS’s @import with the ability to import Sass and CSS stylesheets, providing access to mixins, functions, and variables and combining multiple stylesheets’ CSS together. Unlike plain CSS imports (extra HTTP requests while rendering), Sass imports are handled entirely during compilation.

  • Same basic syntax as CSS @import, plus comma-separated lists of files.
  • Imported content is evaluated as if it appeared at the @import location.
  • Members become globally available after the import.
  • Importing the same file again evaluates it again (CSS can duplicate).
💡
Beginner tip

Read legacy @import so you can follow older tutorials—then rewrite new work with @use so every name has a clear namespace.

⚠️ What’s Wrong With @import?

Official docs list serious issues:

  • All variables, mixins, and functions become globally accessible—hard to find definitions.
  • Libraries must prefix every member to avoid collisions.
  • @extend is also global and hard to predict.
  • Each import re-executes the file and can bloat CSS output.
  • No private members or private placeholder selectors for downstream files.

The module system (@use / @forward) addresses all of these problems.

📝 Syntax

styles.scss
// Single file (extension optional)
@import "foundation/code";

// Multiple files in one rule
@import "foundation/code", "foundation/lists";

// Nested (scopes CSS)
.theme-sample {
  @import "theme";
}

⚙️ How Import Evaluation Works

Official docs: when Sass imports a file, that file is evaluated as though its contents appeared directly in place of the @import. Mixins, functions, and variables become available, and CSS is inserted at that point. Members defined before the import are also visible inside the imported file.

⚠️
Duplicate imports

If the same stylesheet is imported more than once, it is evaluated again each time. Style rules can appear multiple times in the CSS output.

🔍 Finding the File

  • Extensions are optional: @import "variables" loads .scss, .sass, or .css.
  • Use forward slashes (even on Windows).
  • Relative paths resolve first; load paths are a fallback.
  • Partials start with _; omit the underscore when importing.
  • A folder’s _index.scss loads when you import the folder.

🎯 Nested Imports

Official docs: imports can nest inside style rules or plain CSS at-rules. Imported CSS is nested in that context. Top-level mixins/functions/variables from the nested import are only available in that nested context.

For authors of the imported file, prefer a mixin (or meta.load-css() in modern code) instead of relying on nested imports.

📄 Plain CSS @imports

Sass leaves some imports as real CSS @imports in the output when:

  • The URL ends with .css
  • The URL begins with http:// or https://
  • The URL is written as url()
  • The import has media queries
styles.scss
@import "theme.css";
@import "http://fonts.googleapis.com/css?family=Droid+Sans";
@import url(theme);
@import "landscape" screen and (orientation: landscape);

🚀 How Do I Migrate?

Official docs: prefer @use. Sass provides a migration tool that converts most @import-based code automatically.

OldModern
@import "tokens";@use "tokens"; then tokens.$gap
Library barrel file@forward partials from one entry
Nested @importMixin include or meta.load-css()

🔁 Differences From @use

@import (legacy)@use (modern)
Member scopeGlobalCurrent file only (namespaced)
Load once?No—re-evaluates each timeYes—once per module
NestingAllowedMust be at file top
URLs per ruleComma lists OKOne URL per rule
StatusDeprecatedRecommended

⚡ Quick Reference

GoalLegacyPrefer instead
Load members + CSS@import "x";@use "x";
Library entrypointImport many files@forward + one @use
Scope third-party CSSNested @importmeta.load-css() / mixin
Real CSS import@import "x.css";Same (passthrough) or link in HTML

Examples Gallery

These examples show how legacy @import behaves so you can recognize and migrate it. Prefer @use in new projects. Open View Compiled CSS for verified output.

📚 Legacy Patterns

How @import combined files and shared members.

Example 1 — Basic Multi-File Import

Comma-separated imports pull CSS from multiple partials.

styles.scss
// foundation/_code.scss
code {
  padding: .25em;
  line-height: 0;
}

// foundation/_lists.scss
ul, ol {
  text-align: left;

  & & {
    padding: {
      bottom: 0;
      left: 0;
    }
  }
}

// style.scss
@import "foundation/code", "foundation/lists";

How It Works

Both partials are inlined at the import site. Modern equivalent: two @use rules (CSS still included once per module).

Example 2 — Global Members

After import, mixins and variables are available without a namespace.

styles.scss
// _tokens.scss
$gap: 8px;

@mixin soft {
  border-radius: 4px;
  padding: $gap;
}

// style.scss
@import "tokens";

.card {
  @include soft;
  margin-bottom: $gap;
}

How It Works

No tokens.$gap prefix—everything is global. That convenience is also why collisions happen. Prefer @use "tokens"; then tokens.$gap.

📈 Nesting, CSS Passthrough & Migration

Scoped imports, real CSS imports, and a modern rewrite.

Example 3 — Nested Import

Imported CSS is nested under the surrounding selector.

styles.scss
// _theme.scss
pre, code {
  font-family: "Source Code Pro", Helvetica, Arial;
  border-radius: 4px;
}

// style.scss
.theme-sample {
  @import "theme";
}

How It Works

Useful for scoping third-party CSS in legacy projects. Modern options: wrap styles in a mixin, or use meta.load-css().

Example 4 — Plain CSS Passthrough

Some imports are left for the browser, not resolved by Sass.

styles.scss
@import "theme.css";
@import url("https://fonts.googleapis.com/css?family=Droid+Sans");
@import "landscape" screen and (orientation: landscape);

How It Works

Because these match the plain-CSS rules ( .css suffix, url(), media query), Sass emits them unchanged for the browser.

Example 5 — Same Idea With @use

Modern rewrite of the global-members pattern.

styles.scss
// _tokens.scss
$gap: 8px;

@mixin soft {
  border-radius: 4px;
  padding: $gap;
}

// style.scss — modern
@use "tokens";

.card {
  @include tokens.soft;
  margin-bottom: tokens.$gap;
}

How It Works

Same CSS result as Example 2, but names are namespaced and the module loads once. This is the pattern to use going forward.

🚀 When You Still See @import

  • Legacy codebases — older tutorials and packages still use it.
  • LibSass projects — no @use; stuck on imports until you switch compilers.
  • Plain CSS imports — fonts/CDN/media-query imports that must stay in CSS.
  • Migration in progress — mixed @import + @use during a transition.

🧠 How Compilation Works

1

Write @import

Point at a partial, folder, or plain CSS URL.

Source
2

Resolve or passthrough

Sass file? Inline it. Plain CSS import pattern? Leave for the browser.

Compile
3

Share globals

Members become global (legacy behavior) and CSS is emitted.

Emit
4

Plan the migration

Replace with @use / @forward before Dart Sass 3.0.

⚠️ Common Pitfalls

  • Using it in new code — deprecated; will be removed in Dart Sass 3.0.
  • Duplicate CSS — importing the same file twice re-emits its rules.
  • Name collisions — everything is global after import.
  • Assuming browser behavior — Sass imports are compile-time unless they match plain-CSS rules.
  • Writing @import "file.css" for Sass loading — the .css suffix forces a plain CSS import.

💡 Best Practices

✅ Do

  • Prefer @use and @forward for all new work
  • Run the Sass migrator on legacy entrypoints
  • Keep genuine CSS imports (fonts/CDN) as plain CSS when needed
  • Document any temporary @import left during migration
  • Upgrade to Dart Sass so you can leave LibSass behind

❌ Don’t

  • Start new projects on @import
  • Import the same stylesheet repeatedly for “safety”
  • Rely on global members without namespaces
  • Nest imports when a mixin would be clearer
  • Ignore deprecation warnings from Dart Sass 1.80+

Key Takeaways

Knowledge Unlocked

Five things to remember about Sass @import

Legacy compile-time imports—deprecated in favor of @use.

5
Core concepts
📦 02

Scope

global members

Legacy
🔁 03

Replace

@use / @forward

Modern
📄 04

CSS import

passthrough rules

Browser
05

Next

migrate early

Plan

❓ Frequently Asked Questions

Yes. As of Dart Sass 1.80.0, @import is deprecated and will be removed in Dart Sass 3.0.0. Prefer @use (and @forward for library entrypoints).
It loads another Sass or CSS stylesheet at compile time, combining CSS and making mixins, functions, and variables available. Unlike browser CSS @import, it does not add extra HTTP requests at render time.
It makes members global, encourages long prefixes, makes @extend unpredictable, can duplicate CSS when a file is imported multiple times, and has no private members.
Prefer rewriting imports as @use / @forward. Sass provides an official migration tool that converts most @import-based code automatically.
When the URL ends with .css, starts with http(s)://, is written as url(), or includes media queries—Sass leaves those as CSS @import in the output.
Yes. Nested imports scope the imported CSS under a selector or at-rule. For new code, prefer a mixin or meta.load-css() instead.
Did you know?

Official Sass docs ship a migrator that can convert most @import-based projects to @use automatically—point it at your entrypoints and review the diff.

Conclusion

Sass @import was the old way to combine stylesheets and share members. It is deprecated as of Dart Sass 1.80 and scheduled for removal in 3.0. Learn it to maintain legacy code—then migrate to @use and @forward.

Continue with @mixin / @include or browse @use.

Next: Sass @mixin and @include

Build reusable style recipes with arguments and content blocks.

@mixin / @include →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful