How to Integrate Astryx with Next.js Using Build Plugins
To integrate Astryx with Next.js, install the @astryxdesign/build package, configure the Babel and PostCSS plugins to compile StyleX with separate class-name prefixes, and use the withAstryx helper in next.config.mjs to enable source-level transpilation of Astryx packages.
Astryx is a design system that uses StyleX for type-safe styling. When integrating it with Next.js, you must compile the design system's TypeScript and StyleX source alongside your own code to ensure proper class-name segregation and CSS layer ordering. The @astryxdesign/build package provides the necessary Babel, PostCSS, and Next.js utilities to automate this process according to the facebook/astryx repository.
Why Use Astryx Build Plugins?
The build plugins solve three specific integration challenges when you integrate Astryx with Next.js:
- Separate CSS Layers – Library styles receive the
astryx-*prefix and emit into theastryx-baselayer, while your application styles use the defaultxprefix and live in theproductlayer. This prevents class-name collisions and ensures theme overrides work predictably. - Source Transpilation – Next.js treats
@astryxdesign/*packages as source code rather than pre-built bundles, allowing the same Babel and PostCSS pipeline to process both the design system and your application. - Simplified Configuration – The
withAstryxhelper automatically configurestranspilePackagesand Webpack'sresolve.conditionNamesto resolve raw sources under thesourcecondition.
Step 1: Install the Build Dependencies
Install the core build plugin and its peer dependencies. The @astryxdesign/build package provides the Babel and PostCSS integration required for the StyleX compilation pipeline.
npm install -D @astryxdesign/build @stylexjs/babel-plugin @babel/core
This provides the compilers necessary to generate the layered CSS output and handle the separate class-name prefixes.
Step 2: Configure the Babel Plugin
Create a babel.config.js file in your project root. The @astryxdesign/build/babel plugin inspects each file's path to determine whether code belongs to the Astryx library or your application. Library files receive the astryx prefix, while application files use the default x prefix.
// babel.config.js
const path = require('path');
module.exports = {
presets: ['next/babel'],
plugins: [
[
'@astryxdesign/build/babel',
{
dev: process.env.NODE_ENV !== 'production',
runtimeInjection: false,
treeshakeCompensation: true,
enableInlinedConditionalMerge: true,
aliases: {
'@astryxdesign/core/*': [path.join(__dirname, 'node_modules/@astryxdesign/core/*')],
'@astryxdesign/core': [path.join(__dirname, 'node_modules/@astryxdesign/core')],
},
unstable_moduleResolution: {type: 'commonJS'},
},
],
],
};
The unstable_moduleResolution setting ensures the plugin correctly resolves StyleX imports from the Astryx packages.
Step 3: Add the PostCSS Plugin
Create postcss.config.js to run StyleX a second time, wrapping the generated CSS in @layer blocks. The appDir parameter tells the plugin where your application code lives so it can distinguish between library and product styles.
// postcss.config.js
const path = require('path');
module.exports = {
plugins: {
'@astryxdesign/build/postcss': {
appDir: 'src',
babelPlugins: [
[
'@stylexjs/babel-plugin',
{
dev: process.env.NODE_ENV !== 'production',
runtimeInjection: false,
treeshakeCompensation: true,
enableInlinedConditionalMerge: true,
aliases: {
'@astryxdesign/core/*': [path.join(__dirname, 'node_modules/@astryxdesign/core/*')],
'@astryxdesign/core': [path.join(__dirname, 'node_modules/@astryxdesign/core')],
},
unstable_moduleResolution: {type: 'commonJS'},
},
],
],
},
},
};
This configuration generates two passes of StyleX output: one for the astryx-base layer and one for the product layer.
Step 4: Configure Next.js
You can configure Next.js manually or use the convenience helper from packages/build/src/next.js. The manual approach gives you full control, while the helper streamlines the setup.
Option A: Manual Configuration
Update next.config.mjs to transpile Astryx packages and resolve the source condition. This forces Webpack to use the raw TypeScript source files instead of pre-built bundles.
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: [
'@astryxdesign/core',
'@astryxdesign/theme-neutral',
'@astryxdesign/lab',
],
webpack: config => {
config.resolve.conditionNames = [
'source', // Prioritizes raw source files
'import',
'require',
'default',
];
return config;
},
};
export default nextConfig;
Option B: Use the withAstryx Helper
Alternatively, import the withAstryx function to automatically apply the configuration.
// next.config.mjs
import {withAstryx} from '@astryxdesign/build/next';
export default withAstryx({
// Additional Next.js configuration options
});
The helper automatically populates transpilePackages and sets the conditionNames array to include source as the first resolver.
Step 5: Declare CSS Layers
Create a layers.css file to define the cascade order. This ensures that Astryx base styles can be overridden by themes and your application code.
/* src/app/layers.css */
@layer reset, astryx-base, astryx-theme, product;
Import this file in your global CSS, followed by the Astryx reset and theme files. The @stylex directive triggers the StyleX compilation.
/* src/app/globals.css */
@import './layers.css';
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/theme-neutral/theme.css';
@stylex;
Placing the layer declarations in a separate file is required because Webpack hoists @import statements, ensuring the layers appear in the correct order before any StyleX-generated CSS.
Summary
- Install the
@astryxdesign/buildpackage along with StyleX Babel dependencies to enable the build pipeline. - Configure Babel to use the Astryx plugin, which applies different
classNamePrefixvalues for library (astryx) and application (x) code. - Set up PostCSS to wrap the compiled CSS in
@layerblocks, separatingastryx-baseandproductlayers. - Configure Next.js to transpile Astryx packages and resolve the
sourcecondition, either manually or via thewithAstryxhelper. - Declare CSS layers in a separate file imported before other styles to ensure correct cascade ordering.
Frequently Asked Questions
What does the withAstryx helper do exactly?
The withAstryx helper, defined in packages/build/src/next.js, automatically adds all necessary Astryx packages to the transpilePackages array and modifies Webpack's resolve.conditionNames to prioritize the source condition. This ensures Next.js resolves the raw TypeScript and StyleX source files from node_modules rather than consuming pre-compiled JavaScript bundles, enabling your Babel and PostCSS pipelines to process them correctly.
Why are CSS layers required when using Astryx with Next.js?
CSS layers are required to prevent specificity conflicts between the design system and your application. The Astryx build plugins emit library styles into the astryx-base layer and your application styles into the product layer. By declaring these layers in a specific order (astryx-base before product), you ensure that application styles can reliably override design system defaults without resorting to excessive specificity or !important declarations.
Can I customize the Babel configuration while using the Astryx plugin?
Yes, you can extend the Babel configuration passed to the Astryx plugins. Both the Babel and PostCSS plugin configurations accept standard StyleX options, including aliases, unstable_moduleResolution, and compiler flags like treeshakeCompensation. You can also add additional Babel presets or plugins alongside the @astryxdesign/build/babel entry in your babel.config.js file.
Does this integration work with Next.js App Router and Server Components?
Yes, the Astryx build plugins are compatible with the Next.js App Router. The source transpilation and CSS layer generation occur during the build process, producing static CSS files that work with both Server Components and Client Components. Ensure your layers.css and globals.css are imported in your root layout file to guarantee the CSS layers are established before any component styles are loaded.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →