MATIN MOLKARA
SERIES: آموزش Next js — PART 27 OF 28

قسمت بیست و هفتم - دیپلوی پروژه 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 باید از قبل شناسایی شوند
// 0 comments
#Next.js#Deployment

نظرات (0)

نظر خود را بنویسید