My Updated Next.js Setup

Published See discussion on Twitter

This is an update to one of my previous blog posts published in January of 2022 here

I've been tinkering with the Layouts features and functionality within Next for quite some time now, and even had the time to refactor this personal site to use the new features. With all that tinkering I figured I would share some of the things that I'm generally doing with my Next.js apps.

Some of this is still a bit rough around the edges, and I’m sure I’ll be re-thinking some of these ideas in the future as well, but I’ll aim to post updates as I make them.

On Directories:

I used to really like the src/ directory functionality within Next, it let me colocate all my things into a single place, making the codebase a bit easier to look at. However since originally the app directory functionality within Next (aka Layouts) didn’t support the same setup, I’ve decided to drop that paradigm.

I’ve now centered around the following directories (roughly):

  • app/ - for pages and layouts
  • lib/ - for shared functionality like hooks or other logic
  • styles/ - for styles, see On Styles below for more details
  • ui/ - for shared components within the application
  • scripts/ - for shared project scripts, these are usually .mjs files

On Styles:

I still use and really enjoy vanilla-extract, and I used to use their default Next.js integration, however it (at the time of writing) still does not work with Layouts in Next.js. So instead what I’ve opted to do is adopt a parallel build step where I’ll compile out .css.ts files before Next.js builds the application.

My current preferred setup is to leverage their rollup integration, which will take any project .css.ts files and compile them to a similar directory structure within the styles/ directory.

Path Aliases:

With all these separate directories, I’ve also adopted TypeScript path aliases, allowing me to import code from any of the above directories via @[directory name], for example:

1import {cx} from '@lib/classnames'
1import {cx} from '@lib/classnames'

This can be accomplished by adding the following to your tsconfig.json file:

1{
2 "compilerOptions": {
3 "baseUrl": ".",
4 "paths": {
5 "@ui/*": ["./ui/*"],
6 "@lib/*": ["./lib/*"],
7 "@styles/*": ["./styles/*"]
8 },
9 }
10}
1{
2 "compilerOptions": {
3 "baseUrl": ".",
4 "paths": {
5 "@ui/*": ["./ui/*"],
6 "@lib/*": ["./lib/*"],
7 "@styles/*": ["./styles/*"]
8 },
9 }
10}

Server Components:

I’m pretty bullish on using a server to power my sites, so I may generally opt-out of the static optimizations that Next.js does and instead force pages to operate as runtime server components + server side rendering. The main way I’ve found that lets me do that is to add the following to any of the pages:

1export const revalidate = 0
2export const dynamic = 'force-dynamic'
1export const revalidate = 0
2export const dynamic = 'force-dynamic'

Summary:

Those are the high level patterns I’ve been following since adopting Layouts, but I’m curious what you have found to be useful! If you have alternative patterns, or additive ones please share them!