قسمت بیست و هفتم - دیپلوی پروژه Next.js و آمادهسازی برای Production
هدف این آموزش این است که پروژه را از حالت development به حالت production ببریم و بدانیم قبل از deploy چه چیزهایی باید بررسی شوند
انتشار پروژه Next.js و آمادهسازی برای Production
تا اینجای مسیر، ما بخشهای اصلی پروژه را ساختهایم:
- احراز هویت ادمین
- داشبورد مدیریت
- CRUD پروژهها
- CRUD پستها
- آپلود تصویر با Cloudinary
- SEO با Metadata و Open Graph
در این قسمت میخواهیم درباره انتشار یا deploy پروژه Next.js صحبت کنیم؛
هدف این آموزش این است که پروژه را از حالت development به حالت production ببریم و بدانیم قبل از deploy چه چیزهایی باید بررسی شوند.
هدف این قسمت
در پایان این آموزش باید بدانید:
- تفاوت development و production چیست
- چه envهایی باید برای production تنظیم شوند
- چطور build بگیرید
- چطور دیتابیس production را تنظیم کنید
- رایجترین خطاهای deploy در پروژههای Next.js + Prisma چیست
- قبل از انتشار نهایی چه چکلیستی را باید بررسی کنید
development vs production
خیلی از چیزهایی که در محیط توسعه بدون مشکل کار میکنند، ممکن است در production خطا بدهند.
چرا؟
چون این دو محیط از چند جهت با هم متفاوتاند:
1. رفتار اجرا
در development شما معمولاً با این دستور کار میکنید:
npm run dev
اما در production پروژه با build نهایی اجرا میشود:
npm run build
npm start
در نتیجه:
- بعضی خطاها فقط هنگام build مشخص میشوند
- بعضی importها یا typeها در dev نادیده گرفته میشوند ولی در build fail میشوند
- بعضی data fetchingها در production رفتار متفاوتی دارند
2. envها
ممکن است در سیستم لوکال شما همه envها درست باشند، اما روی سرور یکی از آنها تنظیم نشده باشد.
3. دیتابیس
در local معمولاً با یک دیتابیس تست یا لوکال کار میکنید، اما در production باید به دیتابیس واقعی متصل شوید.
4. فایلها و مسیرها
در محیط لوکال گاهی به فایلها یا تنظیماتی دسترسی دارید که در production وجود ندارند.
چرا باید قبل از deploy آمادهسازی انجام دهیم؟
Deploy فقط انتقال کد نیست.
Deploy یعنی مطمئن شویم برنامه در شرایط واقعی:
- امن است
- build میشود
- envهای لازم را دارد
- به دیتابیس درست وصل میشود
- فایلها و تصویرها درست لود میشوند
- و کاربر نهایی با خطا روبهرو نمیشود
مرحله اول: بررسی اسکریپتهای پروژه
اول از همه فایل package.json را بررسی کنید.
باید حداقل این اسکریپتها را داشته باشید:
json
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
}
}
اگر از Prisma استفاده میکنید، معمولاً این اسکریپتها هم مفید هستند:
json
{
"scripts": {
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:studio": "prisma studio"
}
}
مرحله دوم: build گرفتن در لوکال
قبل از اینکه پروژه را روی سرور deploy کنید، حتماً در لوکال build بگیرید.
npm run build
این مرحله بسیار مهم است، چون خیلی از مشکلات فقط اینجا مشخص میشوند.
مثلاً:
- import اشتباه
- type error
- route handler خراب
- metadata اشتباه
- خطا در Server Component
- خطا در dynamic route
- مشکل Prisma client
اگر build بدون خطا انجام نشود، deploy هم معمولاً با مشکل روبهرو میشود.
بعد از build، بهتر است اجرای production را هم تست کنید:
npm start
یعنی پروژه را دقیقاً در حالتی که قرار است در production اجرا شود، روی سیستم خودتان تست کنید.
مرحله سوم: متغیرهای محیطی
یکی از مهمترین بخشهای deploy، مدیریت envهاست.
در پروژه شما احتمالاً envهایی شبیه اینها وجود دارند:
env
DATABASE_URL=...
DIRECT_URL=...
ADMIN_EMAIL=...
ADMIN_PASSWORD_HASH=...
CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
بسته به ساختار پروژهتان ممکن است بعضی نامها فرق کنند، اما منطق یکسان است.
نکته مهم
فایل .env.local شما روی سرور deploy نمیشود.
پس باید تمام envهای لازم را در پلتفرم deploy بهصورت جداگانه تنظیم کنید.
چه envهایی معمولاً باید در production تنظیم شوند؟
1. دیتابیس
DATABASE_URL=...
اگر از Prisma با PostgreSQL استفاده میکنید، این مهمترین env شماست.
در بعضی سرویسها مثل Neon، Supabase، Railway یا Render ممکن است علاوه بر آن، DIRECT_URL هم داشته باشید:
env
DIRECT_URL=...
معمولاً:
DATABASE_URLبرای اتصال اپلیکیشنDIRECT_URLبرای migration یا دسترسی مستقیم
استفاده میشود.
2. Cloudinary
env
CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
این envها باید دقیقاً روی production هم تنظیم شوند، وگرنه آپلود تصویر از کار میافتد.
3. احراز هویت یا session
اگر برای session یا token از secret استفاده میکنید، باید در production مقدار امن و واقعی داشته باشید. مثلاً:
env
SESSION_SECRET=...
اگر چنین چیزی در پروژه دارید، هرگز مقدار ضعیف یا test برای production نگذارید.
4. آدرس سایت
خیلی وقتها بهتر است دامنه اصلی سایت را هم در env نگه دارید:
env
NEXT_PUBLIC_SITE_URL=https://your-domain.com
یا اگر فقط سمت سرور لازم دارید:
env
SITE_URL=https://your-domain.com
این مقدار برای:
- canonical
- Open Graph
- sitemap
- robots
- لینکسازی مطلق
بسیار مفید است.
الگوی بهتر برای خواندن envها
بهجای اینکه envها را مستقیم در همه فایلها بخوانید، بهتر است یک فایل متمرکز بسازید.
مثلاً:
txt
lib/env.ts
ts
function required(name: string, value: string | undefined) {
if (!value) {
throw new Error(`Missing required environment variable: ${name}`)
}
return value
}
export const env = {
databaseUrl: required('DATABASE_URL', process.env.DATABASE_URL),
cloudinaryCloudName: required(
'CLOUDINARY_CLOUD_NAME',
process.env.CLOUDINARY_CLOUD_NAME
),
cloudinaryApiKey: required(
'CLOUDINARY_API_KEY',
process.env.CLOUDINARY_API_KEY
),
cloudinaryApiSecret: required(
'CLOUDINARY_API_SECRET',
process.env.CLOUDINARY_API_SECRET
),
siteUrl: required('SITE_URL', process.env.SITE_URL),
}
مزیت این کار:
- اگر envی جا افتاده باشد، زودتر متوجه میشوید
- مدیریت envها متمرکز میشود
- کد تمیزتر میشود
مرحله چهارم: تنظیم metadata برای production
در قسمت SEO گفتیم که بهتر است metadataBase روی دامنه اصلی سایت تنظیم شود.
نسخه بهتر این است که از env استفاده کنید.
مثلاً در app/layout.tsx:
tsx
import type { Metadata } from 'next'
const siteUrl = process.env.SITE_URL || 'http://localhost:3000'
export const metadata: Metadata = {
metadataBase: new URL(siteUrl),
title: {
default: 'Matin Portfolio',
template: '%s | Matin Portfolio',
},
description: 'Professional portfolio built with Next.js.',
}
این کار باعث میشود در local و production آدرسها درست ساخته شوند.
مرحله پنجم: تنظیم next.config.ts
اگر در پروژه از تصاویر Cloudinary استفاده میکنید، باید remote imageها در config مجاز باشند.
مثلاً:
ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'res.cloudinary.com',
},
],
},
}
export default nextConfig
اگر این تنظیم وجود نداشته باشد، در production تصاویر remote شما با خطا مواجه میشوند.
مرحله ششم: تنظیم دیتابیس production
یکی از بزرگترین تفاوتهای local و production، دیتابیس است.
در development
شما شاید با یک دیتابیس لوکال یا یک سرویس تستی کار کرده باشید.
در production
باید یک دیتابیس واقعی و پایدار داشته باشید.
برای مثال:
- PostgreSQL روی Neon
- PostgreSQL روی Supabase
- PostgreSQL روی Railway
- PostgreSQL روی Render
- یا دیتابیس اختصاصی خودتان
Prisma در production
اگر از Prisma استفاده میکنید، چند نکته مهم وجود دارد.
1. DATABASE_URL باید درست باشد
کوچکترین اشتباه در URL باعث میشود کل اپ بالا نیاید.
2. Prisma Client باید generate شود
معمولاً در فرآیند build این اتفاق میافتد، اما بسته به محیط deploy، گاهی لازم است مطمئن شوید که prisma generate اجرا شده است.
3. migrationها باید اعمال شوند
اگر schema شما تغییر کرده و migration اعمال نشده باشد، اپلیکیشن با ساختار قدیمی دیتابیس اجرا میشود و خطا میدهد.
آیا migration را در production بزنیم؟
اگر از Prisma migration استفاده میکنید، برای production معمولاً از این دستور استفاده میشود:
npx prisma migrate deploy
این دستور migrationهای آماده را روی دیتابیس production اعمال میکند.
تفاوت با migrate dev
دستور زیر برای development است:
npx prisma migrate dev
اما برای production بهتر است از:
npx prisma migrate deploy
استفاده شود.
اگر seed دارید چه؟
اگر پروژه شما نیاز دارد که داده اولیه داشته باشد، مثل:
- ادمین اولیه
- تنظیمات اولیه سایت
- دستهبندیهای اولیه
میتوانید seed هم داشته باشید.
مثلاً:
npx prisma db seed
اما دقت کنید seed در production باید با احتیاط اجرا شود.
نمیخواهید دادههای حساس تکراری یا خراب شوند.
برای ادمین اولیه، بهتر است seed شما idempotent باشد؛ یعنی اگر ادمین از قبل وجود دارد، دوباره ساخته نشود.
نمونه seed برای ادمین اولیه
مثلاً:
ts
import { prisma } from '@/lib/prisma'
import bcrypt from 'bcrypt'
async function main() {
const email = process.env.ADMIN_EMAIL
const password = process.env.ADMIN_PASSWORD
if (!email || !password) {
throw new Error('Missing ADMIN_EMAIL or ADMIN_PASSWORD')
}
const existing = await prisma.admin.findUnique({
where: { email },
})
if (existing) {
console.log('Admin already exists')
return
}
const passwordHash = await bcrypt.hash(password, 12)
await prisma.admin.create({
data: {
email,
passwordHash,
},
})
console.log('Admin created')
}
main()
.catch((error) => {
console.error(error)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})
این فقط یک نمونه است و باید با مدل واقعی پروژه خودتان هماهنگ شود.
مرحله هفتم: تفاوت فایلهای local و production
در local ممکن است از این فایلها استفاده کنید:
txt
.env
.env.local
اما در production معمولاً envها را در dashboard سرویس deploy وارد میکنید.
مثلاً در Vercel یا هر سرویس مشابه:
- نام متغیر
- مقدار متغیر
- environment مربوطه
نکته
هیچوقت .env.local را commit نکنید.
حتماً فایل .gitignore شما باید شامل این موارد باشد:
.env
.env.local
.env.*.local
اگر env حساسی را accidentally commit کردهاید، فقط حذف فایل کافی نیست.
باید secret را تغییر دهید، چون قبلاً نشت کرده است.
مرحله هشتم: تست routeهای مهم قبل از deploy
قبل از deploy نهایی، چند بخش حیاتی را حتماً تست کنید:
1. لاگین ادمین
- آیا session درست ساخته میشود؟
- آیا cookie درست ست میشود؟
- آیا routeهای محافظتشده درست کار میکنند؟
2. CRUD پروژهها
- ساخت پروژه
- ویرایش پروژه
- حذف پروژه
- نمایش پروژه در بخش public
3. CRUD پستها
- ساخت پست
- ویرایش پست
- حذف پست
- نمایش پست در بلاگ
4. آپلود تصویر
- آیا API آپلود کار میکند؟
- آیا Cloudinary envها درست هستند؟
- آیا URL تصویر در دیتابیس ذخیره میشود؟
5. SEO
- آیا title و description درست هستند؟
- آیا Open Graph URLها معتبرند؟
- آیا canonicalها درست ساخته میشوند؟
مرحله نهم: بررسی صفحات dynamic و notFound
در production، routeهای dynamic خیلی مهماند.
مثلاً:
/blog/[slug]
/projects/[slug]
مطمئن شوید اگر slug وجود نداشت:
- صفحه خطای مناسب نمایش داده میشود
- از
notFound()استفاده شده - metadata صفحه خراب نمیشود
این مورد در local گاهی نادیده گرفته میشود، اما در production روی UX و حتی crawl شدن صفحات اثر دارد.
خطاهای رایج deploy در پروژههای Next.js
حالا برویم سراغ رایجترین خطاهایی که معمولاً هنگام deploy پیش میآیند.
خطای ۱: env تعریف نشده
نمونه مشکل:
Missing required environment variable
یا:
process.env.SOMETHING is undefined
دلیل
env لازم را در پلتفرم deploy وارد نکردهاید.
راهحل
- همه envها را لیست کنید
- روی production دوباره وارد کنید
- بعد redeploy بزنید
خطای ۲: Prisma نمیتواند به دیتابیس وصل شود
نمونه مشکل:
Can't reach database server
دلیلهای رایج
DATABASE_URLاشتباه است- دیتابیس خاموش است
- IP یا شبکه محدود شده
- SSL تنظیم نشده
- provider اشتباه است
راهحل
- URL را دقیق بررسی کنید
- اتصال را از داشبورد سرویس دیتابیس تست کنید
- اگر سرویس دیتابیس تنظیمات خاص SSL دارد، آن را اعمال کنید
خطای ۳: migration اعمال نشده
نمونه مشکل:
- فیلد جدید در Prisma model وجود دارد
- اما جدول production هنوز آن ستون را ندارد
نتیجه
کوئریها fail میشوند.
راهحل
قبل یا هنگام deploy، این دستور را اجرا کنید:
npx prisma migrate deploy
خطای ۴: تصاویر Cloudinary نمایش داده نمیشوند
دلیلهای رایج
next.config.tsبرایres.cloudinary.comتنظیم نشده- URL تصویر اشتباه ذخیره شده
- از
next/imageبدون remotePatterns استفاده شده
راهحل
config را بررسی کنید:
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'res.cloudinary.com',
},
],
}
خطای ۵: کدی در dev کار میکند ولی build fail میشود
دلیل
خیلی وقتها در dev همهچیز ظاهراً درست است، اما build سختگیرتر است.
مثلاً:
- type اشتباه
- import نادرست
- استفاده اشتباه از browser API در Server Component
- export اشتباه در routeها
- metadata در Client Component
راهحل
همیشه قبل از deploy این دو دستور را بزنید:
npm run build
npm start
خطای ۶: استفاده اشتباه از window یا document
اگر در Server Component یا کد سروری از window، document یا localStorage استفاده کنید، production build ممکن است fail شود.
راهحل
این APIها فقط باید در Client Component استفاده شوند:
tsx 'use client'
یا داخل event handlerها / effectها.
خطای ۷: routeهای محافظتشده در production درست کار نمیکنند
دلیلهای رایج
- cookie درست تنظیم نشده
- secure cookie فقط روی HTTPS کار میکند
- session secret متفاوت است
- domain یا path cookie اشتباه است
راهحل
- تنظیمات cookie را برای production بررسی کنید
- اگر از secure cookie استفاده میکنید، روی HTTPS تست کنید
- session logic را در production جداگانه تست کنید
خطای ۸: metadata و canonical اشتباهاند
مثلاً:
- هنوز
localhost:3000در metadataBase مانده - sitemap و robots آدرس production ندارند
- canonicalها به دامنه لوکال اشاره میکنند
راهحل
از env برای SITE_URL استفاده کنید و قبل از deploy همه URLها را بررسی کنید.
مرحله دهم: بررسی عملکرد پایه production
حتی اگر این قسمت درباره performance عمیق نباشد، چند بررسی ساده خیلی مهم است:
- آیا تصاویر با
next/imageنمایش داده میشوند؟ - آیا Client Componentهای غیرضروری کم هستند؟
- آیا صفحه ادمین سنگین نشده؟
- آیا queryهای تکراری بیدلیل ندارید؟
- آیا metadata داینامیک بهینه شده است؟
اگر صفحهای فقط برای نمایش داده است، بهتر است تا حد امکان Server Component باقی بماند.
مرحله یازدهم: لاگها را جدی بگیرید
در production، console.error و logهای کنترلشده بسیار ارزشمند هستند.
مثلاً در route handlerها:
ts
try {
// logic
} catch (error) {
console.error('Create project error:', error)
return Response.json(
{ error: 'Failed to create project.' },
{ status: 500 }
)
}
برای کاربر، پیام عمومی میفرستیم.
برای خودمان، خطای واقعی را log میکنیم.
نکته
هیچوقت جزئیات حساس مثل:
- password
- token
- env secret
- connection string
را log نکنید.
مرحله دوازدهم: تست دستی production-like
یک تست خیلی خوب این است که بعد از build، پروژه را مثل production اجرا کنید و این مسیرها را چک کنید:
/
/blog
/blog/[slug]
/projects
/projects/[slug]
/admin/login
/admin
/admin/projects
/admin/posts
همچنین این عملیات را انجام دهید:
- لاگین
- ساخت پروژه
- ساخت پست
- آپلود تصویر
- ویرایش
- حذف
- خروج از حساب
اگر همه اینها در حالت npm start درست کار کنند، احتمال موفق بودن deploy خیلی بالاتر است.
ساختار پیشنهادی برای آمادهسازی deploy
اگر بخواهیم یک روند تمیز داشته باشیم، قبل از deploy این مراحل خوب است:
1. پاکسازی و بازبینی
- حذف کدهای آزمایشی
- حذف logهای بیاستفاده
- حذف فایلهای اضافی
2. بررسی type و build
npm run build
3. بررسی envها
- local
- production
4. بررسی migration
npx prisma migrate deploy
5. تست اجرای production
npm start
6. deploy نهایی
نمونه چکلیست env برای این پروژه
برای پروژهای با stack فعلی شما، این چکلیست مفید است:
-
DATABASE_URL -
DIRECT_URLدر صورت نیاز -
CLOUDINARY_CLOUD_NAME -
CLOUDINARY_API_KEY -
CLOUDINARY_API_SECRET -
SITE_URL -
SESSION_SECRETیا secret مشابه - env مربوط به admin seed در صورت استفاده
نمونه چکلیست فنی قبل از deploy
-
npm installبدون خطا انجام میشود -
npm run buildبدون خطا انجام میشود -
npm startبدون خطا اجرا میشود - Prisma schema با دیتابیس هماهنگ است
- migrationها آمادهاند
- remote image config تنظیم شده است
- metadataBase درست است
- canonical و OG URLها به production اشاره میکنند
- routeهای admin محافظت شدهاند
- آپلود تصویر کار میکند
- create / update / delete برای پروژهها کار میکند
- create / update / delete برای پستها کار میکند
- صفحات public بدون خطا render میشوند
-
notFound()برای slug نامعتبر درست کار میکند
خطاهایی که بهتر است قبل از انتشار رفع شوند
اگر هر کدام از این موارد وجود دارد، بهتر است قبل از deploy حل شوند:
- استفاده از داده mock در بخشی از production
- وابستگی به localhost
- envهای hardcoded در کد
- secretها داخل repository
- queryهای بدون هندل خطا
- فرمهایی که خطای server را نمایش نمیدهند
- صفحههایی که بدون داده crash میکنند
- metadata ناقص یا URLهای اشتباه
آیا الان باید deploy کنیم؟
اگر این موارد را دارید، بله، پروژه به مرحله deploy نزدیک شده:
- CRUD کامل
- احراز هویت
- آپلود تصویر
- SEO پایه
- دیتابیس production-ready
- build سالم
یعنی پروژه شما فقط یک نمونه آموزشی نیست و میتواند نسخه آنلاین واقعی داشته باشد.
چکلیست نهایی این قسمت
- تفاوت development و production را میدانیم
- envهای لازم را شناسایی کردهایم
- پروژه را با
npm run buildتست کردهایم - اجرای production را با
npm startتست کردهایم -
DATABASE_URLو تنظیمات Prisma را آماده کردهایم - migrationهای production را بررسی کردهایم
- تنظیمات Cloudinary را بررسی کردهایم
-
next.config.tsبرای تصاویر remote درست است - metadata و
SITE_URLدرست تنظیم شدهاند - routeهای مهم را دستی تست کردهایم
- خطاهای رایج deploy را بررسی کردهایم
تمرین پیشنهادی
برای محکمکاری بیشتر، این تمرینها را انجام دهید:
تمرین 1
یک فایل lib/env.ts بسازید و تمام envهای پروژه را متمرکز مدیریت کنید.
تمرین 2
یک seed ایمن برای ساخت ادمین اولیه پیادهسازی کنید.
تمرین 3
همه routeهای admin و public را در حالت npm start دستی تست کنید و هر خطا را یادداشت کنید.
تمرین 4
اگر هنوز localhost جایی در metadata یا config مانده، آن را به env مبتنی بر SITE_URL منتقل کنید.
تمرین 5
یک صفحه not-found.tsx سفارشی برای بخش public بسازید.
جمعبندی
در این قسمت، درباره مهمترین کار قبل از آنلاین شدن پروژه صحبت کردیم: آمادهسازی برای production و deploy.
یاد گرفتیم که:
- dev و production یکی نیستند
- envها باید دقیق و کامل باشند
- build گرفتن قبل از deploy ضروری است
- Prisma و دیتابیس production نیاز به توجه ویژه دارند
- routeهای مهم باید دستی تست شوند
- و خطاهای رایج deploy باید از قبل شناسایی شوند