Stylus @Import Decision Guide: Modular Stylesheets Without Ambiguity
Stylus offers multiple @import forms and path-resolution modes. This guide compares them, explains trade-offs, and shows how to validate a modular build with the 0.54.8 CLI.
31 Dec 2025, 15:19 UTC

Stylus gives you several ways to pull one file into another, but the choice is not cosmetic. Because the project reached end-of-life with version 0.54.8 in 2020, your import strategy has to compensate for fragile path resolution and incomplete IDE tooling. The practical takeaway: use explicit extensions for project files, reserve extension-less imports for carefully configured include paths, and switch to @require for shared libraries so you do not emit duplicate CSS.
The Decision and Its Constraints
The decision is how to compose .styl files into a maintainable set. You are constrained by three realities: the last stable release is 0.54.8 with no active maintenance; build environments vary between the CLI and bundler loaders; and path resolution is the most common failure point. Any strategy you pick must be deterministic across those environments.
Comparing Supported Import Forms
| Form | Resolution behavior | Best for | Primary risk |
|---|---|---|---|
@import 'name' | Tries .styl, .css, .js in sequence | Quick prototypes with --include set | Ambiguous if the same basename exists with different extensions |
@import 'name.styl' | Loads the exact Stylus file | Project modules you control | Breaks if the file is renamed or moved without updating the import |
@import 'name.css' | Loads plain CSS; skips Stylus compilation | Vendor stylesheets and npm packages | Cannot use Stylus variables or mixins inside the imported file |
@require 'name' | One-time inclusion that helps avoid circular dependency loops | Shared variables, mixins, and functions | Not a drop-in replacement if you rely on repeated CSS output |
Trade-offs Behind the Table
Extension-less imports depend on mangling order. If both theme.styl and theme.css exist, the resolver picks one based on its internal sequence. In a monorepo or when npm packages are present, that ambiguity becomes a build hazard.
Explicit .styl imports remove guesswork but create tight coupling between import statements and filesystem names. A refactor that renames a partial forces you to hunt down every import string.
.css imports are the correct tool for third-party assets, but they are inert: no variable substitution, no nesting, no mixins. Treat them as opaque blobs.
@require changes the output model. A file required twice appears once in the compiled CSS. For design tokens and mixins this is desirable; for component partials that intentionally repeat selectors, it is not.
Include paths (--include or -I) decouple imports from relative directory structure. The CLI flag works, and dedicated loaders for webpack, Parcel, and Gulp are documented to respect include paths, but you must confirm the behavior with your specific loader version.
Concrete Implementation and Validation
Assume a project rooted at ./ with the following layout:
src/
styles/
tokens.styl
components/
button.styl
main.styl
tokens.styl holds a variable:
primary = #333
components/button.styl consumes it:
.button
color primary
main.styl imports both without relative paths:
@import 'tokens'
@import 'components/button'
Run the compiler from the project root. You need Stylus installed locally or globally; no elevated system permissions are required for a local install.
stylus --compile --include ./src/styles main.styl -o output.css
Expected check: open output.css and confirm the .button rule contains the resolved color value, not the literal identifier primary. If the token is unresolved, the import path or include flag is wrong.
To validate one-time behavior, temporarily add a second @import 'tokens' line and recompile. The variable definition should not duplicate in the output. Replace one line with @require 'tokens' and confirm the output stays stable.
For package resolution, install a known CSS package and import it by name. The CLI provides a --resolve option for package imports; bundler loaders expose equivalent resolve or paths configuration. If resolution fails, verify that configuration matches the CLI include path.
npm install normalize.css
@import 'normalize.css'
Limitations and Maintenance Reality
- Unmaintained runtime. Stylus has not received security patches since 2020. Pin the version in
package.jsonand audit your build pipeline for Node compatibility. - Nesting specificity. Deeply nested rules can produce selector specificity that differs subtly from Sass or Less. Test compiled output rather than assuming parity.
- IDE support. Syntax highlighting and import resolution are limited compared with mainstream preprocessors, raising the cost of large refactors.
- Path fragility. Relative imports that work under the CLI may fail under a bundler if the loader is not configured identically.
How to Check the Result
- Run
stylus --versionand record the actual version; the last stable release is documented as 0.54.8. - Execute the compile command above and inspect
output.cssfor unresolved tokens or duplicated blocks. - If you use a bundler, compare its CSS output with the CLI output. Differences usually point to path-resolution configuration gaps.
Because Stylus is no longer actively maintained, treat these checks as part of every build, not as a one-time setup task.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.