From lightningcss

lightningcss latest releaselightningcss supported Pythonslightningcss licenselightningcss monthly downloadslightningcss total downloads

lightningcss binds the Rust CSS engine behind Parcel to Python through process_stylesheet. It is a cascade-aware optimizer, not just a minifier: alongside whitespace and value compaction it drops declarations overridden elsewhere in the sheet, merges rules, adds or strips vendor prefixes, and rewrites syntax down to a configured browser-target set, so it can reach a smaller result than a value-safe minifier can. That target-driven approach makes it the CSS transform stage in Parcel and a common build-time optimizer for web bundles.

turbohtml covers the same ground with turbohtml.clean.minify_css(), a value-safe minifier. It applies only transforms that hold on any conformant browser, so its default output needs no target list, parses to the same cascade everywhere, minifies faster, and recovers from malformed input that lightningcss rejects. The CSSMinify baseline year opts into newer-syntax shorthand merges when you are ready to require them.

turbohtml vs lightningcss

Dimension

turbohtml

lightningcss

Scope

Value-safe CSS minify (full sheet and inline declarations)

Cascade-aware CSS optimizer: minify, prefix, bundle, CSS modules

Feature breadth

Whitespace + value compaction, shortest colors, unit/number trimming, constant calc() folding, shorthand and adjacent-rule merges

All of that plus cross-sheet dead-declaration removal, target-driven syntax rewriting, vendor prefixing, @import bundling

Performance

2-3x faster minify on the shared corpus (see Performance)

Smaller output on most inputs by trading target configuration for size

Typing

Fully typed, frozen CSSMinify config object

Typed bindings over the Rust engine

Dependencies

Native C extension in turbohtml, no extra dependency

Native Rust extension

Maintenance

Maintained within turbohtml

Tracks the Parcel/lightningcss Rust project

Feature overlap

The minify surface ports 1:1:

  • lightningcss.process_stylesheet(css, minify=True) -> turbohtml.clean.minify_css().

  • Whitespace collapse, shortest hex/color forms, redundant unit and leading-zero trimming, and constant calc() folding are applied by both.

  • Adjacent-rule and shorthand merging: turbohtml merges the value-safe cases by default and the newer-syntax cases (inset, flex gap, two-value overflow) when you set baseline.

What turbohtml adds

  • Value-safe by construction: every transform round-trips to the same cascade on any conformant browser, so there is no target list to configure and no way to emit syntax a target cannot parse.

  • WHATWG error recovery: turbohtml minifies malformed stylesheets that lightningcss’s parser rejects, for example a media query in foundation.css that the WHATWG rules accept.

  • Faster runs: 2-3x quicker minify on the shared corpus.

  • Inline-declaration minify via turbohtml.clean.minify_css_inline() for bare style-attribute declaration lists, without a surrounding selector or braces.

  • Custom-property values and string contents stay byte-exact, as CSS Variables 1 requires.

What lightningcss has that turbohtml does not

  • Cross-sheet cascade optimization: lightningcss removes declarations overridden elsewhere in the sheet. turbohtml does not, because the result depends on which browsers you support; there is no value-safe equivalent.

  • Target-driven syntax rewriting to a browser-target set. turbohtml’s baseline gates newer-syntax shorthand merges but does not rewrite down to an arbitrary older-target set.

  • Vendor prefixing (adding or removing prefixes for a target). No equivalent; turbohtml preserves the input’s prefixes.

  • @import bundling and CSS-modules transforms. No equivalent; turbohtml minifies a single stylesheet in place.

Performance

lightningcss produces the smaller output on most of the corpus – up to five percent under turbohtml – because it optimizes for a browser-target set: it removes declarations overridden across the sheet and emits syntax those targets support. turbohtml applies only transforms that hold on any conformant browser, so its default output needs no target list and parses to the same cascade everywhere; the CSSMinify baseline year opts into the newer-syntax shorthand merges when you are ready to require them. turbohtml also minifies two to three times faster, comes out ahead on normalize.css, and recovers from malformed CSS that lightningcss rejects: foundation.css raises a parse error on a media query the WHATWG rules accept, where turbohtml minifies all six stylesheets. Each ratio is against turbohtml:

stylesheet

turbohtml

lightningcss

size

time

size

time

normalize.css (6 kB)

1.7 kB

88.6 µs

1.8 kB (1.02x)

44.6 µs (0.6x)

pico.css (90 kB)

80.8 kB

1.46 ms

80.0 kB (0.99x)

1.43 ms (1.0x)

animate.css (93 kB)

72.8 kB

684 µs

68.8 kB (0.95x)

1.16 ms (1.8x)

bootstrap.css (274 kB)

229.1 kB

6.62 ms

228.7 kB (0.998x)

4.14 ms (0.7x)

bulma.css (745 kB)

680.7 kB

19.1 ms

674.3 kB (0.99x)

11.2 ms (0.6x)

Reach for lightningcss when you can pin a browser-target set and want the last few percent of size; reach for turbohtml when you want value-safe output with no configuration, faster runs, and tolerance of real-world CSS.

How to migrate

The import and the call are the only change:

# lightningcss
from lightningcss import process_stylesheet

process_stylesheet(css, minify=True)

# turbohtml
from turbohtml.clean import minify_css

minify_css(css)

lightningcss

turbohtml

process_stylesheet(css, minify=True)

turbohtml.clean.minify_css()

process_stylesheet(css, minify=True, targets=...)

turbohtml.clean.minify_css() with CSSMinify (baseline gates newer-syntax merges)

No equivalent (full-sheet input only)

turbohtml.clean.minify_css_inline() for style-attribute declaration lists

from turbohtml.clean import minify_css

print(minify_css("a {\n  color: #ffffff;\n  margin: 0px 0px;\n}"))
a{color:#fff;margin:0}

To target a newer browser baseline, pass CSSMinify; the year gates the newer-syntax merges, much as lightningcss’s targets gate its own:

from turbohtml.clean import CSSMinify, minify_css

print(minify_css("a{top:0;right:0;bottom:0;left:0}", CSSMinify(baseline=2021)))
a{inset:0}

Gotchas and pitfalls

  • lightningcss removes declarations overridden elsewhere in the sheet and rewrites syntax for its targets; turbohtml does neither by default, because both depend on which browsers you support. Set baseline to recover the newer-syntax merges, but the whole-sheet cascade optimization has no value-safe equivalent.

  • lightningcss aborts on a stylesheet its parser rejects; turbohtml follows the WHATWG error-recovery rules, so it minifies inputs like foundation.css that lightningcss will not parse.

  • lightningcss can add or drop vendor prefixes for a target; turbohtml preserves the input’s prefixes as written.

  • turbohtml keeps custom-property values and string contents byte-exact; do not expect the internal whitespace of a var() value or a string literal to be collapsed.

  • Both are native extensions (Rust versus C), so neither offers a pure-Python fallback.