For AI agents: the complete documentation index is available at https://rspack.rs/llms.txt, the full documentation bundle is available at https://rspack.rs/llms-full.txt, and this page is available as Markdown at https://rspack.rs/guide/builtin-loaders/lightningcss-loader.md.
close

Lightning CSS loader

Lightning CSS is a high performance CSS parser, transformer and minifier written in Rust. It supports parsing and transforming many modern CSS features into syntax supported by target browsers, and also provides a better compression ratio.

Rspack provides a built-in builtin:lightningcss-loader, which is based on Lightning CSS to transform CSS. It can replace the postcss-loader and autoprefixer for CSS syntax downgrading, prefixing, and other functionalities, offering better performance.

Warning

Please note that Lightning CSS strictly requires standards-compliant CSS input. When non-standard CSS is processed by the builtin:lightningcss-loader, styles may be ignored or produce unexpected results (Undefined Behavior). To ensure that styles are correctly applied, avoid using non-standard CSS syntax or browser-specific proprietary syntax, and instead use standard CSS writing practices that conform to W3C specifications.

Example

To use builtin:lightningcss-loader in your project, you need to configure it as follows.

rspack.config.mjs
import { rspack } from '@rspack/core';

export default {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'builtin:lightningcss-loader',
            options: {
              targets: 'ie 10',
            },
          },
          // ... other loaders
        ],
      },
    ],
  },
};

Type declarations

You can use the LightningcssLoaderOptions type exported by @rspack/core to enable type hints:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'builtin:lightningcss-loader',
            /** @type {import('@rspack/core').LightningcssLoaderOptions} */
            options: {
              targets: 'ie 10',
            },
          },
          // ... other loaders
        ],
      },
    ],
  },
};

Options

Below are the configurations supported by builtin:lightningcss-loader. For detailed configuration, please refer to lightningcss document.

type LightningcssFeatureOptions = {
  nesting?: boolean;
  notSelectorList?: boolean;
  dirSelector?: boolean;
  langSelectorList?: boolean;
  isSelector?: boolean;
  textDecorationThicknessPercent?: boolean;
  mediaIntervalSyntax?: boolean;
  mediaRangeSyntax?: boolean;
  customMediaQueries?: boolean;
  clampFunction?: boolean;
  colorFunction?: boolean;
  oklabColors?: boolean;
  labColors?: boolean;
  p3Colors?: boolean;
  hexAlphaColors?: boolean;
  spaceSeparatedColorNotation?: boolean;
  fontFamilySystemUi?: boolean;
  doublePositionGradients?: boolean;
  vendorPrefixes?: boolean;
  logicalProperties?: boolean;
  selectors?: boolean;
  mediaQueries?: boolean;
  color?: boolean;
};

type Targets = {
  android?: string;
  chrome?: string;
  edge?: string;
  firefox?: string;
  ie?: string;
  ios_saf?: string;
  opera?: string;
  safari?: string;
  samsung?: string;
};

type LightningcssLoaderOptions = {
  minify?: boolean;
  errorRecovery?: boolean;
  targets?: string[] | string | Targets;
  include?: LightningcssFeatureOptions;
  exclude?: LightningcssFeatureOptions;
  drafts?: Drafts;
  nonStandard?: NonStandard;
  pseudoClasses?: PseudoClasses;
  unusedSymbols?: string[];
};

targets

  • Type: string | string[] | Targets

Browserslist query string or a Targets object specifying browser versions.

Default browser targets

When targets is not set, the loader gets its browser targets from Rspack's target. For example, with browserslist or browserslist:modern, you do not need to repeat the configuration in the loader. Lightning CSS only supports browser targets, so it cannot get browser versions from non-browser targets such as node.

When Rspack target is not set, the loader also tries to get browser targets from its default value. See target default behavior for details.

If no Browserslist configuration is found, Rspack defaults to web, which does not specify browser versions. The loader's targets then remains unset, and you can configure it as needed.

Here are some examples of setting targets.

  • Setting a browserslist query string:
const loader = {
  loader: 'builtin:lightningcss-loader',
  /** @type {import('@rspack/core').LightningcssLoaderOptions} */
  options: {
    targets: 'ie 10',
  },
};
  • Setting an array of browserslist query strings:
const loader = {
  loader: 'builtin:lightningcss-loader',
  /** @type {import('@rspack/core').LightningcssLoaderOptions} */
  options: {
    targets: ['chrome >= 87', 'edge >= 88', '> 0.5%'],
  },
};
  • Setting a Targets object:
const loader = {
  loader: 'builtin:lightningcss-loader',
  /** @type {import('@rspack/core').LightningcssLoaderOptions} */
  options: {
    targets: {
      chrome: '95.0',
      safari: '13.2',
    },
  },
};

errorRecovery

  • Type: boolean
  • Default: true

Control how Lightning CSS handles invalid CSS syntax.

By default, this option is enabled, meaning that when invalid CSS rules or declarations are parsed, Lightning CSS will skip them and emit warnings, while omitting them from the final output without interrupting the compilation process.

Ignoring warnings

If you confirm that these warnings can be ignored, you can use ignoreWarnings to filter out the warnings from LightningCSS.

For example, ignore all warnings:

rspack.config.mjs
export default {
  ignoreWarnings: [
    (warning) => /LightningCSS parse warning/.test(warning.message),
  ],
};

You can also use regular expressions to ignore specific warnings.

Disabling errorRecovery

If you set errorRecovery to false, Lightning CSS will throw a compilation error and interrupt the build process when parsing any invalid CSS syntax:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'builtin:lightningcss-loader',
            /** @type {import('@rspack/core').LightningcssLoaderOptions} */
            options: {
              errorRecovery: false,
            },
          },
        ],
      },
    ],
  },
};

drafts

  • Type: { customMedia?: boolean }
  • Default: undefined

Enable parsing of draft CSS syntax.

Set drafts.customMedia to true to parse @custom-media rules. The loader expands custom media references and removes their definitions when include.customMediaQueries is set or when browser targets are configured. Lightning CSS treats custom media as unsupported in every browser, so any browser targets enable this transform, including targets derived from Rspack's target. Set exclude.customMediaQueries to keep custom media unchanged. Because include takes precedence over exclude and include.mediaQueries already contains include.customMediaQueries, this only works when both include.customMediaQueries and include.mediaQueries are disabled.

For example, with drafts: { customMedia: true } and include: { customMediaQueries: true }, the following CSS:

@custom-media --wide (min-width: 800px);

@media (--wide) {
  .example {
    color: red;
  }
}

is transformed into:

@media (width >= 800px) {
  .example {
    color: red;
  }
}

Custom media is resolved within each CSS file. If a file uses a name that it doesn't define, the loader emits a warning and leaves all custom media in that file unchanged. A circular definition causes a build error. Lightning CSS does not expand custom media in @import conditions, so in a file that uses custom media there, the loader also leaves all custom media unchanged.

Sharing custom media between files

To use the same definitions in several files, add them to each file before this loader runs. For example, with a small loader that appends a shared file:

custom-media-loader.mjs
import fs from 'node:fs/promises';
import path from 'node:path';

const definitions = path.resolve(import.meta.dirname, 'src/breakpoints.css');

export default async function loader(source) {
  this.addDependency(definitions);
  return `${source}\n${await fs.readFile(definitions, 'utf-8')}`;
}
rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.css$/,
        type: 'css',
        use: [
          {
            loader: 'builtin:lightningcss-loader',
            options: {
              drafts: { customMedia: true },
              include: { customMediaQueries: true },
            },
          },
          './custom-media-loader.mjs',
        ],
      },
    ],
  },
};

this.addDependency() rebuilds each file when the shared definitions change. Definitions can come after the queries that use them, so appending keeps @import rules first and source map positions unchanged. Appended definitions override definitions with the same name in the file.

Alternatively, leave custom media to LightningCssMinimizerRspackPlugin, which resolves it across each output CSS file. Enable minimizerOptions.drafts.customMedia in the plugin, and leave drafts.customMedia disabled in this loader, or set exclude.customMediaQueries with both include.customMediaQueries and include.mediaQueries disabled, so that the loader keeps the definitions. Custom media is then only expanded in minimized output, and each name must be defined in the same output file as the queries that use it.