Sebastian Gomez
CSS and Styles in Next.js
When we work with styles in React applications, we run into two main kinds of styles: the global styles and the component styles. Let's see how to work with them in Next.js.
Valid as of Next.js 16: The concepts in this post (global styles versus styles scoped to a component, and CSS Modules to avoid collisions) are still fully valid. What changed since 2022 is where you import global styles: with the App Router (the default and recommended model in Next.js 16) you do it in app/layout.tsx, while with the Pages Router (legacy, but still supported) you do it in pages/_app.jsx. We'll cover both.
Global styles with the App Router
If you created your project with create-next-app in its current form, you're using the App Router. Here the entry point is the root layout: the app/layout.tsx (or app/layout.js) file. To apply global styles, we simply import them there:
// app/layout.tsx
// Import the global styles once, in the root layout.
import './globals.css';
// The root layout wraps the entire application.
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}And that's it. Unlike the Pages Router, here you don't have to create any special file by hand: the root layout already exists in your project and is the natural place for global styles.
Global styles with the Pages Router (legacy)
If your project uses the Pages Router, the entry point is different. But which entry point is that in Next.js?
That entry point already exists internally when we use Next.js, but if we want to import global styles, we have no choice but to override it ourselves. We just need to create a file in the pages folder and name it _app.jsx.
Note: In the Pages Router, global CSS can only be imported from pages/_app.jsx. If you try to import global CSS from any other file, Next.js will throw an error. This is exactly the practical reason we need to create (and use) this file.
Since we're overriding the application's entry point, the minimum we need to write so that its normal behavior isn't altered is the following:
// pages/_app.jsx
// Default export a function called 'App'.
export default function App({ Component, pageProps }) {
// Return the current page's 'Component' (a React component).
// It also passes the 'pageProps' down using the "spread" operator {...pageProps}.
return <Component {...pageProps} />;
}Now, to add our global styles, we simply import the CSS files there:
// pages/_app.jsx
// Import 'flexbox.css' with a relative path (it's a local project file).
import '../flexbox.css';
// Import 'mystyles.css', with custom project styles.
import '../mystyles.css';
// Default export a function called 'App'.
export default function App({ Component, pageProps }) {
// Return the current page's 'Component' and pass it the 'pageProps'.
return <Component {...pageProps} />;
}Tip: Pay attention to the path. import '../flexbox.css' uses a relative path because it's a local file. If you wrote import 'flexbox.css' (without ./ or ../), Next.js would look for it inside node_modules as if it were a package, and it would fail unless it really is one.
Component styles with CSS Modules
When we don't want to use global CSS, Next.js supports CSS Modules. This works the same way in both the App Router and the Pages Router, and it lets us isolate each component's CSS to avoid collisions between class names.
We can import a CSS Module anywhere in our application. To create one, we use a special syntax in the file name: styles.module.css. That .module.css suffix is what enables the isolation.
This makes CSS Modules a perfect solution for styling components. For example, we could place the styles right next to the component that uses them:
components/
button.jsx
button.module.cssAnd inside the component we import it as an object of class names:
// components/button.jsx
// Each class from the .module.css comes in as a property of the 'styles' object,
// with a unique name generated by Next.js to avoid collisions.
import styles from './button.module.css';
export default function Button() {
return <button className={styles.primary}>Click</button>;
}Personally, I prefer to use a different solution when styling my React applications. We'll look at it in the next post.
Conclusions
In this post we learned how to use global styles and component styles in React applications with Next.js. We saw where global styles go in both the App Router (app/layout.tsx) and the Pages Router (pages/_app.jsx), and how to use CSS Modules to isolate our components' CSS and avoid collisions.
Exercises to practice
- Create a Next.js 16 project with the App Router and set up a
globals.cssfile, importing it fromapp/layout.tsx. - Build a component using a CSS Module (
button.module.css) and check it in the browser. - Experiment with different styling methods and find the one that best fits your needs.
3-point summary
- Next.js supports both global styles and component styles in React applications.
- Global styles are imported in
app/layout.tsx(App Router) or inpages/_app.jsx(Pages Router, legacy but supported); with the Pages Router, global CSS can only be imported from_app. - CSS Modules (
*.module.css) isolate each component's CSS to avoid collisions, and every developer can choose the styling solution that best fits their needs.
That's all. I hope this post is useful to you and that you can apply it to a project you have in mind.
Leave me a comment if it helped, if you want to add an opinion, or if you have any questions. And remember, if you liked it, you can also share it using the social links below. Good luck with your styles!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.