CSS Boundaries
Boss CSS can split generated CSS by directory using *.boss.css boundary files. This lets you load styles only where
they’re used while still hoisting shared rules to common ancestors or global styles.css.
What is a boundary?
A boundary is a user‑created *.boss.css file placed anywhere in your source tree. Boss CSS overwrites these files with
generated output. You import the boundary file where you want its styles to load.
Example layout:
src/
app/
app.boss.css
page.tsx
admin/
admin.boss.css
page.tsx
marketing/
marketing.boss.css
page.tsx
.bo$$/styles.css
In this setup:
src/app/app.boss.cssreceives styles used insrc/app/**(unless hoisted).src/app/admin/admin.boss.cssreceives styles used insrc/app/admin/**(unless hoisted).src/marketing/marketing.boss.cssreceives styles used insrc/marketing/**..bo$$/styles.cssis the global fallback (also used for hoisted rules).
How boundaries are resolved
Boss CSS uses filesystem paths (not the import graph):
- Each parsed source file is mapped to the nearest boundary in the same directory or an ancestor.
- If no boundary exists above it, the rule lands in
.bo$$/styles.css. - If multiple boundaries exist in the same directory, the first one (alphabetically) wins and a warning is logged.
Hoisting (criticality)
When the same rule appears in more than one boundary, Boss CSS hoists it upward:
- By default, when a rule appears in 2 boundaries, it moves to their nearest common ancestor boundary.
- If no ancestor boundary exists, it lands in
.bo$$/styles.css.
You can tune the threshold:
export default {
css: {
boundaries: {
criticality: 3,
},
},
}
Rule identity (what counts as “the same rule”)
Rules are matched by normalized selector + declarations, including @media and @keyframes wrappers. Whitespace and
trailing semicolons do not affect matching.
Examples treated as the same rule:
.btn {
color: red;
}
.btn {
color: red;
}
Root declarations and custom CSS
:rootvariables (tokens) are tracked per source and follow the same hoisting rules.$$.csscustom blocks are also attributed and hoisted by boundary usage.@importrules always stay in the global stylesheet (.bo$$/styles.css).
Config options
export default {
css: {
boundaries: {
criticality: 2,
ignore: ['**/dist/**'],
},
},
}
criticality: number of boundaries a rule must appear in before it is hoisted.ignore: extra glob patterns to exclude from boundary discovery.node_modulesis always ignored.
Build / PostCSS / Watch behavior
- PostCSS: the plugin processes
.bo$$/styles.cssand any*.boss.cssfiles, and overwrites them each run. - npx boss-css build / watch: writes
.bo$$/styles.cssand all boundary files; watch ignores boundary outputs to avoid rebuild loops. - npx boss-css compile: does not write CSS files (it only rewrites source output). Boundary files are unchanged in compile mode.
Practical usage
- Create empty boundary files:
touch src/app/app.boss.css
- Import them where needed:
// src/app/layout.tsx (or equivalent)
import './app.boss.css'
- Keep them empty. Boss CSS overwrites them on build/postcss runs.
Notes and caveats
- Boundary discovery happens every run, so adding/removing boundary files is safe.
- Because boundaries are outputs, do not hand‑edit them. Keep them empty and committed if you want consistent imports.
- Filesystem based and NOT import‑graph based.