Skip to main content

Usage with Next.js

FSD is compatible with Next.js in both the App Router version and the Pages Router version if you solve the main conflict β€” the app and pages folders.

App Router​

Conflict between FSD and Next.js in the app layer​

Next.js suggests using the app folder to define application routes. It expects files in the app folder to correspond to pathnames. This routing mechanism does not align with the FSD concept, as it's not possible to maintain a flat slice structure.

The solution is to move the Next.js app folder to the project root and import FSD pages from src, where the FSD layers are, into the Next.js app folder.

You will also need to add a pages folder to the project root, otherwise Next.js will try to use src/pages as the Pages Router even if you use the App Router, which will break the build. It's also a good idea to put a README.md file inside this root pages folder describing why it is necessary, even though it's empty.

β”œβ”€β”€ app                              # App folder (Next.js)
β”‚ β”œβ”€β”€ api
β”‚ β”‚ └── get-example
β”‚ β”‚ └── route.ts
β”‚ └── example
β”‚ └── page.tsx
β”œβ”€β”€ pages # Empty pages folder (Next.js)
β”‚ └── README.md
└── src
β”œβ”€β”€ app
β”‚ └── api-routes # API routes
β”œβ”€β”€ pages
β”‚ └── example
β”‚ β”œβ”€β”€ index.ts
β”‚ └── ui
β”‚ └── example.tsx
β”œβ”€β”€ widgets
β”œβ”€β”€ features
β”œβ”€β”€ entities
└── shared

Example of re-exporting a page from src/pages in the Next.js app:

app/example/page.tsx
export { ExamplePage as default, metadata } from '@/pages/example';

Middleware​

If you use middleware in your project, it must be located in the project root alongside the Next.js app and pages folders.

Instrumentation​

The instrumentation.js file allows you to monitor the performance and behavior of your application. If you use it, it must be located in the project root, similar to middleware.js.

Pages Router​

Conflict between FSD and Next.js in the pages layer​

Routes should be placed in the pages folder in the root of the project, similar to app folder for the App Router. The structure inside src where the layer folders are located remains unchanged.

β”œβ”€β”€ pages                            # Pages folder (Next.js)
β”‚ β”œβ”€β”€ _app.tsx
β”‚ β”œβ”€β”€ api
β”‚ β”‚ └── example.ts # API route re-export
β”‚ └── example
β”‚ └── index.tsx
└── src
β”œβ”€β”€ app
β”‚ β”œβ”€β”€ custom-app
β”‚ β”‚ └── custom-app.tsx # Custom App component
β”‚ └── api-routes
β”‚ └── get-example-data.ts # API route
β”œβ”€β”€ pages
β”‚ └── example
β”‚ β”œβ”€β”€ index.ts
β”‚ └── ui
β”‚ └── example.tsx
β”œβ”€β”€ widgets
β”œβ”€β”€ features
β”œβ”€β”€ entities
└── shared

Example of re-exporting a page from src/pages in the Next.js pages:

pages/example/index.tsx
export { Example as default } from '@/pages/example';

Custom _app component​

You can place your Custom App component in src/app/_app or src/app/custom-app:

src/app/custom-app/custom-app.tsx
import type { AppProps } from 'next/app';

export const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<>
<p>My Custom App component</p>
<Component { ...pageProps } />
</>
);
};
pages/_app.tsx
export { App as default } from '@/app/custom-app';

Route Handlers (API routes)​

Use the api-routes segment in the app layer to work with Route Handlers.

Be mindful when writing backend code in the FSD structure β€” FSD is primarily intended for frontends, meaning that's what people will expect to find. If you need a lot of endpoints, consider separating them into a different package in a monorepo.

src/app/api-routes/get-example-data.ts
import { getExamplesList } from '@/shared/db';

export const getExampleData = () => {
try {
const examplesList = getExamplesList();

return Response.json({ examplesList });
} catch {
return Response.json(null, {
status: 500,
statusText: 'Ouch, something went wrong',
});
}
};
app/api/example/route.ts
export { getExampleData as GET } from '@/app/api-routes';

Additional recommendations​

  • Use the db segment in the shared layer to describe database queries and their further use in higher layers.
  • Caching and revalidating queries logic is better kept in the same place as the queries themselves.

See also​