Bootstrap 6 with npm
Set up a Bootstrap 6 project that compiles Sass to CSS using npm command-line tools, with no JavaScript bundler. Bootstrap's pre-built JS bundle is loaded directly via a <script> tag. Requires Node.js and terminal familiarity.
Workflow
- Step 1: Set up npm and install dependencies
- Step 2: Create the project structure
- Step 3: Configure npm scripts and config files
- Step 4: Import Bootstrap's Sass
- Step 5: Verify
Step 1: Set up npm and install dependencies
-
Create the project and initialize npm:
mkdir my-project && cd my-project npm init -y -
Install Bootstrap and its optional peer dependencies (omit
@floating-ui/domif not using menus/popovers/tooltips; omitvanilla-calendar-proif not using the datepicker):npm i --save bootstrap@6.0.0-alpha.1 @floating-ui/dom vanilla-calendar-pro -
Install the tools to compile and post-process CSS:
npm i --save-dev autoprefixer postcss postcss-cli sass -
Install local dev tooling (watch, run scripts, serve, lint):
npm i --save-dev nodemon npm-run-all sirv-cli stylelint stylelint-config-twbs-bootstrap
Step 2: Create the project structure
mkdir {css,scss}
touch index.html scss/styles.scss postcss.config.js stylelint.config.mjs
Target layout:
my-project/
├── css/
├── scss/
│ └── styles.scss
├── stylelint.config.mjs
├── index.html
├── package-lock.json
├── package.json
└── postcss.config.js
Step 3: Configure npm scripts and config files
-
postcss.config.js— run Autoprefixer after Sass:const autoprefixer = require('autoprefixer') module.exports = { plugins: [ autoprefixer ] } -
index.html— link the compiled CSS and load Bootstrap's pre-built JS bundle (no bundler here, so usedist):<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bootstrap w/ npm</title> <link rel="stylesheet" href="css/styles.css"> </head> <body> <div class="container py-4 px-3 mx-auto"> <h1>Hello, Bootstrap and npm!</h1> <button class="btn-solid theme-primary">Primary button</button> </div> <script type="module" src="node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script> </body> </html> -
package.json— add scripts. Note--load-path=node_modulesso Sass resolvesbootstrap:{ "scripts": { "css-compile": "sass --load-path=node_modules --style expanded --source-map --embed-sources scss:css", "css-prefix": "postcss --config postcss.config.js --replace \"css/*.css\" \"!css/*.min.css\"", "build": "npm-run-all --sequential css-compile css-prefix", "watch": "nodemon --watch scss/ --ext scss --exec \"npm run build\"", "serve": "sirv --port 8080 --dev .", "start": "npm-run-all build --parallel watch serve", "lint": "stylelint \"scss/**/*.scss\"" } } -
stylelint.config.mjs:/** @type {import('stylelint').Config} */ export default { extends: 'stylelint-config-twbs-bootstrap' } -
Start the dev server:
npm start
Step 4: Import Bootstrap's Sass
Add to scss/styles.scss using the modern @use rule (never @import):
// Import all of Bootstrap's CSS
@use "bootstrap/scss/bootstrap";
Customize tokens with with () — include only the keys you want to change:
@use "bootstrap/scss/bootstrap" with (
$root-tokens: (
--border-radius: .25rem,
--spacer: 1.5rem,
)
);
Override CSS custom properties through the token maps ($root-tokens and each component's $*-tokens map), following Customize › Sass. Token names are written unprefixed in Sass (e.g. --border-radius, --spacer); Bootstrap's dist/CDN CSS runs PostCSS to add the --bs- prefix, so compiling the source yourself keeps them unprefixed.
Step 5: Verify
- Run
npm startand openhttp://localhost:8080— the.containerand.btn-solid.theme-primarybutton should be styled once the CSS compiles. - Confirm
css/styles.cssis generated and updates when you editscss/styles.scss(watch is running). - Confirm no console errors from the JS bundle.
- Run
npm run lintto check Sass against Bootstrap's stylelint config. - Bootstrap 6 requires a browser that supports
oklch()andcolor-mix().
For an optimized build that imports only the parts of Bootstrap you use, see the twbs/examples sass-js project.
