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
:
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
:
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
:
import type { AppProps } from 'next/app';
export const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<>
<p>My Custom App component</p>
<Component { ...pageProps } />
</>
);
};
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.
- App Router
- Pages Router
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',
});
}
};
export { getExampleData as GET } from '@/app/api-routes';
import type { NextApiRequest, NextApiResponse } from 'next';
const config = {
api: {
bodyParser: {
sizeLimit: '1mb',
},
},
maxDuration: 5,
};
const handler = (req: NextApiRequest, res: NextApiResponse<ResponseData>) => {
res.status(200).json({ message: 'Hello from FSD' });
};
export const getExampleData = { config, handler } as const;
export { getExampleData } from './get-example-data';
import { getExampleData } from '@/app/api-routes';
export const config = getExampleData.config;
export default getExampleData.handler;
Additional recommendationsβ
- Use the
db
segment in theshared
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.