I’m using Next.js 15 (with the app directory) and Mantine 7 in my project. I'm styling Mantine components using SCSS modules (*.module.scss
), but the styles behave inconsistently depending on how I run the app.
When running the app with next dev --turbo, SCSS module styles are applied correctly to Mantine components.
However, without --turbo
(i.e., just next dev
) or when starting from a build result (next build
→ next start
), the SCSS module styles are not applied at all.
I’ve followed the official Mantine documentation for using Sass with Next.js (https://mantine.dev/styles/sass/#usage-with-nextjs). postcss.config.cjs
and _mantine.scss
file already added on the root of the repo exactly same as what written in the docs.
next.config.mjs
import path from 'node:path';
import bundleAnalyzer from '@next/bundle-analyzer';
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});
export default withBundleAnalyzer({
reactStrictMode: false,
eslint: {
ignoreDuringBuilds: true,
},
experimental: {
optimizePackageImports: ['@mantine/core', '@mantine/hooks'],
},
sassOptions: {
implementation: 'sass-embedded',
additionalData: `@use "${path.join(process.cwd(), '_mantine').replace(/\\/g, '/')}" as mantine;`,
},
});
package.json
{
"name": "my-repo",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"fast": "next dev --turbo",
"build": "next build",
"analyze": "ANALYZE=true next build",
"start": "next start",
"typecheck": "tsc --noEmit",
"lint": "npm run eslint && npm run stylelint",
"eslint": "next lint",
"stylelint": "stylelint '**/*.css' --cache",
"lint:fix": "npm run prettier:write && eslint . --fix",
"jest": "jest",
"jest:watch": "jest --watch",
"prettier:check": "prettier --check \"**/*.{ts,tsx}\"",
"prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
"test": "npm run prettier:check && npm run lint && npm run typecheck && npm run jest",
"storybook": "storybook dev -p 6006",
"storybook:build": "storybook build"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@mantine/core": "7.16.3",
"@mantine/dates": "^7.16.1",
"@mantine/form": "^7.16.1",
"@mantine/hooks": "7.16.3",
"@mantine/modals": "^7.16.3",
"@mantine/notifications": "^7.16.1",
"@next/bundle-analyzer": "^14.2.4",
"@tabler/icons-react": "^3.6.0",
"@tanstack/react-query": "^5.64.2",
"@tanstack/react-query-devtools": "^5.64.2",
"axios": "^1.7.9",
"clsx": "^2.1.1",
"currency.js": "^2.0.4",
"dayjs": "^1.11.13",
"i18next": "^24.2.1",
"i18next-http-backend": "^3.0.2",
"mantine-react-table": "2.0.0-beta.8",
"material-icons": "^1.13.12",
"next": "15.1.7",
"next-auth": "^4.24.11",
"next-i18next": "^15.4.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-i18next": "^15.4.0",
"react-imask": "^7.6.1",
"zod": "^3.24.1",
"zod-validation-error": "^3.4.0"
},
"devDependencies": {
"@babel/core": "^7.24.7",
"@eslint/js": "^9.15.0",
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@storybook/nextjs": "^8.1.10",
"@storybook/react": "^8.1.10",
"@tanstack/eslint-plugin-query": "^5.64.2",
"@testing-library/dom": "^10.1.0",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@types/eslint-plugin-jsx-a11y": "^6",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.8",
"@types/react": "18.3.3",
"babel-loader": "^9.1.3",
"eslint": "^9.15.0",
"eslint-config-mantine": "^4.0.3",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.2",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"postcss": "^8.4.38",
"postcss-preset-mantine": "1.17.0",
"postcss-simple-vars": "^7.0.1",
"prettier": "^3.3.2",
"sass": "^1.85.0",
"sass-embedded": "^1.83.4",
"storybook": "^8.1.10",
"storybook-dark-mode": "^4.0.2",
"stylelint": "^16.6.1",
"stylelint-config-standard-scss": "^13.1.0",
"ts-jest": "^29.1.5",
"typescript": "5.5.2",
"typescript-eslint": "^8.14.0"
},
"packageManager": "yarn@4.6.0"
}
Removing implementation: sass-embedded
in next.config.mjs
do succeed overwrite some scss style module in some components, but still mostly not (especially for font-size
, color
padding
, and many more).
Example like this:
footer.module.scss
.footerLink {
color: var(--mantine-color-neutral-4) !important; // if i added important it applied
transition: color 0.2s ease; // applied
font-size: 16px; // not applied
&:hover {
color: var(--mantine-color-primary-5); // not applied
}
}
.listRoot {
column-count: 1; // applied
column-gap: 42px; // applied
@media (min-width: mantine.$mantine-breakpoint-sm) {
column-count: 2; // applied
}
}
.listText {
line-height: 13.81px; // not applied
}
Why do SCSS module styles only work properly when running the app with next dev --turbo
? How can I ensure the styles also work with next dev
or next build
?
Any insights or guidance would be appreciated! Let me know if more details are needed.
Importing mantine core css file before my custom style fixed the problem.
Like this:
AppProvider.tsx
'use client'
...
import '@mantine/core/styles.css'
import alertClasses from './styles/Alert.module.scss'
// other style modules
const theme = createTheme({
spacing: { '2lg':'24px'},
components: {
Alert: Alert.extend({
defaultProps: {
classNames: alertClasses,
color: 'primary',
},
}),
},
...
})
const AppProvider = ({ children }: Props) => {
return (
<MantineProvider theme={theme}>
<ModalsProvider>
<Notifications position="top-right" autoClose={5000} />
<AppLayout>{children} </AppLayout>
</ModalsProvider>
</MantineProvider>
)
}
export default AppProvider
Previously I imported mantine core css file in root layout.tsx
and it makes my custom style not working, the mantine core css style overwrited my custom style.
Like this:
layout.tsx
...
import '@mantine/core/styles.css'
export default async function RootLayout({ children }: { children: any }) {
return (
<html lang="en" {...mantineHtmlProps}>
<head>
<ColorSchemeScript />
<link rel="shortcut icon" href="/favicon.svg" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
/>
</head>
<body>
<AppProvider>{children}</AppProvider>
</body>
</html>
)
}
AppProvider.tsx
'use client'
...
import alertClasses from './styles/Alert.module.scss'
// other style modules
const theme = createTheme({
spacing: { '2lg':'24px'},
components: {
Alert: Alert.extend({
defaultProps: {
classNames: alertClasses,
color: 'primary',
},
}),
},
...
})