Front-End npm Setup: Sass, Bootstrap 5, Font Awesome 7 and Autoprefixer

Quick Summary

  • Run npm init -y, install bootstrap and @fortawesome/fontawesome-free as dependencies, and sass, postcss, postcss-cli and autoprefixer with --save-dev.
  • npm scripts copy Font Awesome's webfonts, compile the SCSS with Dart Sass and run Autoprefixer, so npm run build and npm run watch do the work.
  • Load Bootstrap and Font Awesome with @use: Sass deprecated @import in Dart Sass 1.80.0 and plans to remove it in Dart Sass 3.0.0.

For a front-end npm setup with Sass, Bootstrap, Font Awesome and Autoprefixer, run npm init -y, install Bootstrap and Font Awesome as dependencies, and install sass, postcss, postcss-cli and autoprefixer as devDependencies. Then add npm scripts that compile your SCSS and run Autoprefixer, so npm run build and npm run watch do the work. In September 2026 the current versions are Bootstrap 5.3.8, Font Awesome Free 7.3.1, Sass 1.105.0, PostCSS 8.5.28, postcss-cli 12.0.0 and Autoprefixer 10.6.1.

The install commands

Shell
npm init -y
npm install bootstrap @fortawesome/fontawesome-free
npm install --save-dev sass postcss postcss-cli autoprefixer
  • npm init -y creates a package.json with default values. Without -y, npm asks for each value first.
  • Bootstrap and Font Awesome go in dependencies, because their code ends up in the CSS you ship. Since npm 5, npm install saves to dependencies by default, so --save is no longer needed. npm also installed @popperjs/core, Bootstrap’s peer dependency, without being asked.
  • The build tools go in devDependencies with --save-dev. sass is Dart Sass, the current Sass compiler; the old node-sass package is deprecated, and npm shows “Node Sass is no longer supported”. postcss is listed next to postcss-cli because the CLI needs it as a peer dependency, and that’s how the postcss-cli README installs it.

The difference between –save and –save-dev explains the two groups in more detail.

npm scripts to build and watch

Add a scripts section and a browserslist line to package.json. This is the whole file after the commands above:

JSON
{
  "name": "my-theme",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "copy:fonts": "node -e \"require('fs').cpSync('node_modules/@fortawesome/fontawesome-free/webfonts', 'webfonts', { recursive: true })\"",
    "build:css": "sass --load-path=node_modules --quiet-deps --style=compressed --no-source-map scss/style.scss css/style.css",
    "prefix:css": "postcss css/style.css --use autoprefixer --replace --no-map",
    "build": "npm run copy:fonts && npm run build:css && npm run prefix:css",
    "watch": "sass --load-path=node_modules --quiet-deps --watch scss/style.scss css/style.css"
  },
  "dependencies": {
    "@fortawesome/fontawesome-free": "^7.3.1",
    "bootstrap": "^5.3.8"
  },
  "devDependencies": {
    "autoprefixer": "^10.6.1",
    "postcss": "^8.5.28",
    "postcss-cli": "^12.0.0",
    "sass": "^1.105.0"
  },
  "browserslist": [
    "defaults"
  ]
}
  • copy:fonts copies Font Awesome’s font files to a webfonts folder next to css, where its CSS looks for them. It uses Node’s own fs.cpSync(), so it works in the Windows command prompt as well as on macOS and Linux.
  • build:css compiles scss/style.scss to css/style.css. --load-path=node_modules lets you write @use "bootstrap/scss/bootstrap" instead of a ../node_modules/… path, and --quiet-deps hides warnings from files found through that load path. --style=compressed minifies the output.
  • prefix:css runs Autoprefixer on the compiled file and overwrites it. Autoprefixer is a PostCSS plugin that adds the vendor prefixes, like -webkit- and -moz-, that your target browsers still need, using data from Can I Use, and removes prefixes they no longer need.
  • browserslist sets those target browsers. defaults means > 0.5%, last 2 versions, Firefox ESR, not dead, according to the Browserslist docs.
  • npm run watch recompiles the CSS each time you save an SCSS file. It skips Autoprefixer, so run npm run build before you deploy.

Tested with npm 11.16 and npm 12.1 on Windows: npm run build copied the four Font Awesome .woff2 files and wrote a 331 KB css/style.css. A user-select: none rule came out with -webkit-user-select and -moz-user-select added, and in a separate check Autoprefixer removed an old -webkit-border-radius. With npm run watch running, saving a change to the SCSS file recompiled the CSS.

The SCSS file: @use instead of @import

Put this in scss/style.scss:

CSS
// Bootstrap, with one of its variables changed
@use "bootstrap/scss/bootstrap" with (
  $primary: #7952b3
);

// Font Awesome Free: the core, then the icon styles you use
@use "@fortawesome/fontawesome-free/scss/fontawesome";
@use "@fortawesome/fontawesome-free/scss/solid";
@use "@fortawesome/fontawesome-free/scss/brands";
@use "@fortawesome/fontawesome-free/scss/regular";

// Your own styles
.site-header {
  display: flex;
  gap: 1rem;
  user-select: none;
}
  • @use loads a file as a module. Sass deprecated @import in Dart Sass 1.80.0, released in October 2024, and plans to remove it in Dart Sass 3.0.0, “no sooner than two years after” 1.80.0. The current release is 1.105.0; Dart Sass 2.0 hasn’t come out yet. Every @import in your own files prints a deprecation warning now.
  • Bootstrap 5.3 still uses @import in its own source, and its Sass documentation still shows @import. You can load it with @use anyway, and with ( … ) sets its variables: in the test, .btn-primary rendered with the #7952b3 background. Without --quiet-deps, the compile printed 20 deprecation warnings from Bootstrap’s files plus a note that 310 more were left out. Bootstrap says these warnings don’t prevent compilation or use.
  • Font Awesome 7’s SCSS already uses @use. Load fontawesome, the core, plus the styles you use: solid, regular and brands in the free version. Its CSS expects the fonts in ../webfonts, relative to the compiled file. To keep them elsewhere, configure the path before the other lines with @use "@fortawesome/fontawesome-free/scss/variables" with ($font-path: "../fonts/fontawesome");.

An icon then takes one tag, for example <i class="fa-solid fa-house"></i>. In headless Chrome 153, the solid, regular and brands icons loaded their three font files from webfonts/.

The earlier version of this post loaded Font Awesome with paths like @use '../node_modules/@fortawesome/fontawesome-free/scss/solid.scss';. That still compiles with Font Awesome 7.3.1; the load path just makes it shorter. To convert your own @import rules, the Sass team’s migrator does it for you: npx sass-migrator module --migrate-deps scss/style.scss changed an @import "variables"; to @use "variables"; and its $brand to variables.$brand in a test. For more on splitting SCSS into files, see SCSS partials.

Problems you may run into

  • “sass is not recognized” or “sass: command not found”. If the NODE_ENV environment variable is set to production, npm install skips devDependencies without any warning. On a machine with that setting, npm install installed only Bootstrap, Popper and Font Awesome, and npm run build failed with 'sass' is not recognized as an internal or external command. Install with npm install --include=dev, or unset the variable.
  • A warning about blocked install scripts. npm 12 doesn’t run install scripts you haven’t approved. With npm 12.1, the install reported that the script of @parcel/watcher, which Sass uses for watching, was blocked; npm run build and npm run watch still worked.
  • Icons don’t appear. The browser can’t find the font files. Check that webfonts/ sits next to css/ on the server, or that $font-path points to where you put them.

In a WordPress theme, enqueue css/style.css with wp_enqueue_style() and upload the css and webfonts folders; node_modules doesn’t need to be on the server.

Share on X (opens in a new tab) Share on LinkedIn (opens in a new tab) Share on Facebook (opens in a new tab)

ChatGPT (opens in a new tab) Claude (opens in a new tab) Gemini (opens in a new tab) Perplexity (opens in a new tab) Grok (opens in a new tab)

More Insights

See More