---
title: SSR/SSG Strategy for Next.js Pages
impact: HIGH
impactDescription: Critical for SEO and initial page load performance
tags: performance, nextjs, ssr, ssg, seo
---
## Паспорт документа

- Статус документа: living standard
- Актуально на: 28 марта 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении инженерной практики, CI/CD, архитектурных правил или локального workflow
- Область применения: внутренние rule/reference-card документы для инженерной команды
- Связанные документы:
  - [Индекс Agents](../README.md)
  - [Команды разработки](../commands.md)
  - [Инженерные принципы](../../governance/engineering-principles.md)

## SSR/SSG Strategy for Next.js Pages

**Impact: HIGH**

Every public-facing page must be server-rendered for SEO and performance. Choose the right rendering strategy per page.

### Rendering Strategy by Page

| Page | Strategy | Reason |
|------|----------|--------|
| Home / Catalog | SSR with cache | Dynamic filters, SEO critical |
| Item detail | SSR with revalidate | SEO critical, updated by sellers |
| Seller profile | SSR with revalidate | SEO relevant |
| Login / Register | Static | No dynamic data |
| Seller dashboard | Client-side | Auth required, no SEO |
| Admin panel | Client-side | Auth required, no SEO |

### Implementation

```typescript
// SSR with fetch cache (catalog)
// app/page.tsx
export default async function CatalogPage({ searchParams }) {
  const items = await api.catalog.getItems(searchParams);
  return <CourseFeed items={items} />;
}

// SSR with revalidation (item detail)
// app/item/[slug]/page.tsx
export default async function ItemDetailPage({ params }) {
  const item = await api.catalog.getItemBySlug(params.slug);
  if (!item) notFound();

  return <ItemDetail item={item} />;
}

// Generate metadata for SEO
export async function generateMetadata({ params }) {
  const item = await api.catalog.getItemBySlug(params.slug);
  return {
    title: `${item.name} | Qadam`,
    description: item.shortDescription?.slice(0, 160),
    openGraph: { title: item.name, images: [item.imageUrl] },
  };
}
```

### Rules
- **Public pages**: Always SSR or SSG — never client-side only
- **Dashboard pages**: Client-side is OK (behind auth, no SEO)
- **Metadata**: Every public page must have `generateMetadata`
- **Loading states**: Use `loading.tsx` for Suspense boundaries, not client-side spinners
- **Error boundaries**: Use `error.tsx` for error handling at route level
