Stylus: Choosing Between Mixins and Extend for CSS Reusability
Deciding between Mixins and @extend in Stylus is a balance of CSS file size and selector complexity. Learn when to use dynamic mixins versus static extensions to optimize your stylesheets.
30 Jun 2026, 06:02 UTC

The Dilemma: Redundancy vs. Selector Complexity
When building a scalable design system in Stylus, you often face a choice between mixins and @extend. The core problem is a trade-off between CSS file size and selector predictability. Using the wrong approach leads to either bloated stylesheets that slow down page loads or a "selector soup" that makes debugging specificity nearly impossible.
Comparing Mixins and Extend
Mixins act like functions that inject properties directly into a rule. Extend, conversely, tells Stylus to group the current selector with another existing selector in the final CSS output.
| Feature | Mixins | @extend |
|---|---|---|
| Output Method | Copies properties into the rule | Groups selectors together |
| Parameters | Supported (Dynamic values) | Not supported (Static only) |
| CSS File Size | Increases with every use | Stays lean via grouping |
| Specificity | Predictable | Can create complex chains |
When to Use Mixins
Use mixins when you need flexibility. If a style needs to change based on the context—such as a button color that varies by theme—a mixin is the only viable option. Because mixins inject properties directly, they do not create dependencies between unrelated classes, making them safer for components that move across different parts of a layout.
When to Use Extend
Use @extend for strict hierarchies. If you have a base class (e.g., .btn) and several variations (e.g., .btn-primary, .btn-danger) that share 90% of the same static properties, extending the base class prevents the CSS from repeating the same 10 lines of code for every variation.
Implementation Example
The following example demonstrates both approaches. To run this, you need the stylus CLI installed via npm. Run the command stylus input.styl -o output.css in your terminal.
// 1. Mixin for dynamic spacing (Flexible)
flexible-padding(size)
padding: size size 0 size
// 2. Base class for extension (Static)
.base-card
border: 1px solid #ccc
border-radius: 4px
display: block
// Applying the logic
.profile-card
@extend .base-card
flexible-padding(20px)
background: #f9f9f9
.product-card
@extend .base-card
flexible-padding(10px)
background: #fff
Analyzing the Compiled Result
If you inspect the compiled output.css, you will see how Stylus handled the two different instructions:
/* The @extend grouped the selectors to save space */
.base-card, .profile-card, .product-card {
border: 1px solid #ccc;
border-radius: 4px;
display: block;
}
/* The mixin injected unique values into each rule */
.profile-card {
padding: 20px 20px 0 20px;
background: #f9f9f9;
}
.product-card {
padding: 10px 10px 0 10px;
background: #fff;
}
Risks and Limitations
- Specificity Bloat: Overusing
@extendcan lead to massive comma-separated lists in your CSS. If you extend a class that is nested deep within another selector, Stylus may generate highly specific selectors that are difficult to override. - Debugging: In browser developer tools, an extended element will show the styles coming from the grouped selector list. This can make it harder to trace exactly which Stylus rule generated the style compared to the direct property injection of a mixin.
- Execution: Ensure you are using a modern version of the Stylus compiler (1.x+), as legacy versions may handle selector grouping differently.
Verification Step
To verify your decision, compile your stylesheet and search for the base class used in your @extend. If you see the base class listed alongside multiple other classes in a single rule, the extension is working. If you see the same block of properties repeated multiple times across your file, you are using mixins for static styles and should consider switching to @extend to reduce file size.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.