Next.js ile Kullanım
src Klasörü
Section titled “src Klasörü”Next.js, projenin kök dizininde (root) veya src klasöründe özel app veya pages klasörlerinin bulunmasını bekler. Genellikle, Next.js klasörlerini projenin kök dizinine yerleştirmek, src klasörünün yalnızca FSD kodunu içermesini sağladığı için daha kolaydır; ancak bu zorunlu değildir.
App Router
Section titled “App Router”Next.js, App Router için app klasörünü ve Pages Router için pages klasörünü kullanır; bu durum FSD katman adlarıyla çakışır. Bu çakışmayı çözmek için, app yerine _app ve pages yerine _pages gibi FSD katmanları için ön ek (prefix) içeren adlar kullanın. Bu yaklaşım resmi linter ile de uyumludur.
Dizinapp Next.js app klasörü
Dizinapi/
Dizinget-example/
- route.ts
Dizinexample/
- page.tsx
Dizinsrc/
Dizin_app/ FSD katmanı
Dizinapi-routes/ API rotaları
- …
Dizin_pages/ FSD katmanı
Dizinexample/
- index.ts
Dizinui/
- example.tsx
Dizinwidgets/
- …
Dizinfeatures/
- …
Dizinentities/
- …
Dizinshared/
- …
Next.js app içinde src/_pages katmanından bir sayfanın yeniden dışa aktarılması (re-export) örneği:
export { ExamplePage as default, metadata } from '@/_pages/example';Sunucu ve istemci public API’leri
Section titled “Sunucu ve istemci public API’leri”Next.js App Router’da, istemcide kullanılabilecek modüller ve yalnızca sunucuya özel (server-only) modüller tek bir dilim (slice) içinde birlikte bulunabilir. Yalnızca sunucuya özel bir modül index.ts dosyasından dışa aktarılırsa, bir İstemci Bileşeni (Client Component) o dilimi içe aktardığında yalnızca sunucuya özel yan etkiler istemci modül grafiğine yayılabilir ve bu da derleme (build) hatalarına yol açabilir.
Bu sorun ortaya çıktığında, public API’ye index.server.ts ekleyin.
index.server.ts: Sunucu Bileşenleri (Server Components) veyaserver-onlyile işaretlenmiş veri erişim fonksiyonları gibi yalnızca sunucuda içe aktarılması gereken modüller.
Middleware
Section titled “Middleware”Projenizde middleware kullanıyorsanız, Next.js app ve pages klasörlerinin yanı sıra projenin kök dizininde yer almalıdır.
Instrumentation
Section titled “Instrumentation”instrumentation.js dosyası, uygulamanızın performansını ve davranışını izlemenizi sağlar. Eğer kullanıyorsanız, middleware.js dosyasına benzer şekilde projenin kök dizininde bulunmalıdır.
Pages Router
Section titled “Pages Router”pages katmanında FSD ve Next.js arasındaki çakışma
Section titled “pages katmanında FSD ve Next.js arasındaki çakışma”Rotalar, App Router için app klasörüne benzer şekilde projenin kök dizinindeki pages klasörüne yerleştirilmelidir. Katman klasörlerinin bulunduğu src içindeki yapı değişmeden kalır.
Dizinpages/ Pages klasörü (Next.js)
- _app.tsx
Dizinapi/
- example.ts API rotası yeniden dışa aktarımı
Dizinexample/
- index.tsx
Dizinsrc/
Dizin_app/ FSD katmanı
Dizincustom-app/
- custom-app.tsx Özel App bileşeni
Dizinapi-routes/
- get-example-data.ts API rotası
Dizin_pages/ FSD katmanı
Dizinexample/
- index.ts
Dizinui/
- example.tsx
Dizinwidgets/
- …
Dizinfeatures/
- …
Dizinentities/
- …
Dizinshared/
- …
Next.js pages içinde src/_pages katmanından bir sayfanın yeniden dışa aktarılması örneği:
export { Example as default } from '@/_pages/example';Özel _app bileşeni
Section titled “Özel _app bileşeni”Özel App bileşeninizi src/_app/_app veya src/_app/custom-app içine yerleştirebilirsiniz:
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';Rota İşleyicileri (API rotaları)
Section titled “Rota İşleyicileri (API rotaları)”Rota İşleyicileri (Route Handlers) ile çalışmak için _app katmanındaki api-routes segmentini kullanın.
FSD yapısında backend kodu yazarken dikkatli olun — FSD öncelikle frontend için tasarlanmıştır, yani insanların bulmayı bekleyeceği şey budur. Çok sayıda endpoint’e ihtiyacınız varsa, bunları bir monorepo içinde farklı bir pakete ayırmayı düşünün.
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;Ek öneriler
Section titled “Ek öneriler”- Veritabanı sorgularını ve bunların üst katmanlardaki sonraki kullanımlarını tanımlamak için
sharedkatmanındakidbsegmentini kullanın. - Sorguları önbelleğe alma (caching) ve yeniden doğrulama (revalidating) mantığını, sorguların kendisiyle aynı yerde tutmak daha iyidir.