
بیشتر کار پرفورمنس توی Next.js زرنگبازی نیست — یه چکلیسته. اینجا اونی که واقعاً اثر داره رو میبینیم، تقریباً به ترتیب نسبت زحمت به بازده.
۱. عکسها و فونتها — بردهای تضمینی
next/image خودکار AVIF/WebP سرو میکنه و تا وقتی width/height (یا fill + والد سایزدار) تنظیم شده باشه باعث layout shift نمیشه — همین بهتنهایی معمولاً CLS رو درست میکنه.
next/font فایل فونت رو self-host میکنه و موقع build تزریقش میکنه، پس نه درخواست render-blocking به یه CDN فونت هست، نه layout shift ناشی از swap شدن فونت.
۲. پیشفرض استاتیک، انتخابی داینامیک
هرجا داده request-specific نیست با ISR رندر استاتیک کن، و فقط جایی سراغ رندر کاملاً داینامیک برو که صفحه واقعاً به دادهی هر-درخواست نیاز داره (وضعیت auth، شخصیسازی). یه پست بلاگ یا صفحهی پروژه تقریباً هیچوقت نیازی به داینامیک بودن نداره.
export const revalidate = 3600; // حداکثر هر یه ساعت دوباره تولید شه
export async function generateStaticParams() {
const posts = await postRepository.findAllPublished();
return posts.map((post) => ({ slug: post.slug }));
}۳. دادهی کند و غیرحیاتی رو با Suspense استریم کن
هرچی که کند و برای اولین paint لازم نیست رو توی Suspense boundary خودش با یه fallback سبک بپیچون، تا بقیهی صفحه فوری تحویل داده بشه بهجای اینکه منتظر کندترین کوئری بمونه.
<Suspense fallback={<CommentsSkeleton />}>
<Comments postId={post.id} />
</Suspense>۴. موازی fetch کن، نه پشتسرهم
// کند — fetch دوم بدون هیچ دلیلی منتظر تمومشدن اولی میمونه.
const project = await getProject(slug);
const related = await getRelatedProjects(project.tags);
// سریع — هر دو درخواست همزمان شلیک میشن.
const [project, allProjects] = await Promise.all([getProject(slug), getAllProjects()]);
const related = allProjects.filter((p) => p.tags.some((t) => project.tags.includes(t)));۵. باندل کلاینت رو کوچیک نگه دار
"use client" رو تا جای ممکن پایین درخت هل بده — یه صفحه میتونه ۹۵٪ Server Component باشه با فقط یه برگ تعاملی کوچیک؛ کل صفحه یا layout رو client نکن فقط چون یه دکمه به onClick نیاز داره.
کامپوننتهای کلاینت سنگین زیر fold (چارتها، ادیتورهای متن غنی، مودالها) رو با next/dynamic لیزیلود کن تا جاوااسکریپتشون توی باندل اولیه نباشه.
آیکونها و utilityها رو با نام از کتابخونههایی که پشتیبانی میکنن import کن، و برای اونایی که خودشون تمیز tree-shake نمیشن، experimental.optimizePackageImports رو توی next.config تنظیم کن.
۶. خواندنها رو کش و دیداپلیکیت کن
fetch() توی App Router خودکار بهازای هر درخواست memoize میشه. برای هرچی که از fetch رد نمیشه — یه فراخوانی ORM، یه کوئری مستقیم دیتابیس — با cache() از React بپیچونش تا همون دیداپلیکیت بهازای هر درخواست رو بگیری، پس پنج تا Server Component که یه پروژهی یکسان میخوان، فقط یهبار میرن سراغ دیتابیس.
import { cache } from "react";
export const getProject = cache(async (slug: string) => {
return prisma.project.findUnique({ where: { slug } });
});۷. قبل از بهینهسازی، اندازه بگیر
سایز روتها رو توی خروجی next build بخون، وقتی چیزی سنگین حس شد @next/bundle-analyzer رو اجرا کن، و Core Web Vitals واقعی (LCP، INP، CLS) رو چک کن نه اینکه حدس بزنی. بهینهسازی یه روتی که از قبل سریعه، وقتی رو هدر میده که یه روت واقعاً کند بهش نیاز داشت.
مطالب بیشتر

احرازهویت با better-auth در Next.js: یه راهاندازی دستاول
راهاندازی دقیق پشت لاگین ادمین همین سایت: کانفیگ سرور، route handler catch-all در Next.js، کلاینت، و محافظت دولایهای middleware + layout که واقعاً /admin رو امن میکنه.

Recharts در Next.js و Tailwind: تمدهی و استایلدهی سفارشی
طبیعیکردن Recharts با سیستم طراحی Tailwind: مرز درست Client Component، وصلکردن رنگها به CSS variable برای dark mode خودکار، tooltip و legend سفارشی، و مدیریت لوکیلهای RTL.