اگر پروژهای دارید که چند سرویس مختلف با Docker اجرا میشوند و یکی از این سرویسها Next.js است، ممکن است در حالت Development با یک مشکل آزاردهنده مواجه شده باشید: تغییرات کد با تأخیر نمایش داده میشوند، Fast Refresh کند است یا حتی باز شدن صفحات نسبت به اجرای معمولی Next.js زمان بیشتری میبرد.
در این شرایط لزوماً لازم نیست کل محیط توسعه را از Docker خارج کنیم. یکی از راهکارهای ساده این است که سرویسهایی مثل دیتابیس، Redis و Backend همچنان داخل Docker اجرا شوند، اما Next.js را مستقیماً روی سیستم خودمان اجرا کنیم.
در این مقاله میبینیم چرا این روش میتواند سرعت محیط توسعه را بهتر کند و چطور آن را مرحلهبهمرحله پیادهسازی کنیم.
چه زمانی این مقاله به درد شما میخورد؟
این روش زمانی ارزش امتحان کردن دارد که شرایطی شبیه موارد زیر دارید:
- پروژه شما با Docker Compose اجرا میشود.
- Next.js هم یکی از سرویسهای Docker Compose است.
- سورس پروژه Next.js با Bind Mount به کانتینر متصل شده است.
- تغییر یک فایل باعث میشود Fast Refresh یا Hot Reload با تأخیر انجام شود.
- اجرای
npm run devخارج از Docker به شکل محسوسی سریعتر است. - میخواهید Backend، دیتابیس، Redis، Celery یا سرویسهای دیگر همچنان Dockerized باقی بمانند.
هدف این نیست که Docker را از محیط توسعه حذف کنیم. قرار است فقط بخشی که در زمان توسعه بیشترین تعامل را با فایلهای پروژه دارد، یعنی Next.js، روی سیستم Local اجرا شود.
چرا Next.js داخل Docker ممکن است در Development کند شود؟
در حالت Development، Next.js دائماً با فایلهای پروژه درگیر است.
وقتی فایلی را تغییر میدهید، محیط توسعه باید تغییر را تشخیص دهد، فایلهای موردنیاز را دوباره پردازش کند و نتیجه جدید را در اختیار مرورگر قرار دهد.
اگر سورس پروژه را با Bind Mount وارد کانتینر کرده باشید، مثلاً:
volumes:
- ./frontend:/appفایلهای روی سیستم شما باید در اختیار محیط داخل کانتینر قرار بگیرند.
Docker نیز Bind Mount را دقیقاً برای همین نوع اشتراک فایل بین Host و Container ارائه میکند.
اما این ارتباط همیشه بدون هزینه نیست.
این موضوع مخصوصاً هنگام استفاده از Docker Desktop روی macOS و Windows بیشتر اهمیت پیدا میکند، چون Docker Desktop کانتینرهای Linux را داخل یک محیط Linux اجرا میکند و اشتراک فایل بین فایلسیستم Host و این محیط میتواند سربار ایجاد کند. خود مستندات Docker نیز اشاره میکنند که File Sharing سربار دارد و اشتراک تعداد زیادی فایل میتواند باعث افزایش مصرف CPU و کاهش کارایی فایلسیستم شود.
در پروژههای Next.js این مسئله میتواند بیشتر احساس شود، چون هنگام Development تعداد زیادی فایل و Dependency وجود دارد و ابزار توسعه باید تغییرات فایلها را مرتب دنبال کند.
Docker حتی برای پروژههای بزرگ قابلیت Synchronized File Shares را ارائه کرده تا عملکرد Bind Mountها را بهتر کند.
بنابراین اگر مشکل اصلی شما مربوط به همین مسیر فایلسیستم باشد، یک راه ساده این است:
Next.js را از Docker خارج کنیم، اما باقی سرویسها را داخل Docker نگه داریم.
ساختار جدید محیط Development
فرض کنید پروژه ما تقریباً چنین سرویسهایی دارد:
PostgreSQL
Redis
Django Backend
Celery Worker
Next.js Frontendدر حالت قبلی همه آنها داخل Docker اجرا میشدند.
اما در حالت جدید ساختار را به شکل زیر تغییر میدهیم:
Docker
├── PostgreSQL
├── Redis
├── Django Backend
└── Celery Worker
Local Machine
└── Next.jsNext.js مستقیماً روی سیستم اجرا میشود و از طریق پورتهایی که Docker روی Host منتشر کرده است با Backend ارتباط برقرار میکند.

مرحله اول: سرویس Next.js را داخل Docker اجرا نکنید
فرض کنیم فایل Development ما docker-compose.dev.yml است.
بهجای بالا آوردن همه سرویسها، فقط سرویسهایی را اجرا میکنیم که میخواهیم داخل Docker باقی بمانند:
docker compose --env-file .env.prod -f docker-compose.dev.yml up -d postgres redis backend
سپس Celery Worker را نیز اجرا میکنیم:
docker compose --env-file .env.prod -f docker-compose.dev.yml up -d celery_worker
نکته مهم این است که در این دستورات سرویس Frontend را اجرا نکردهایم.
بنابراین Docker مسئول اجرای PostgreSQL، Redis، Backend و Celery است، اما Next.js را خودمان روی سیستم اجرا خواهیم کرد.
مرحله دوم: مطمئن شوید Backend از Host قابل دسترسی است
Next.js دیگر داخل Docker Network قرار ندارد.
وقتی Frontend و Backend هر دو داخل Docker باشند، ممکن است بتوانیم با نام سرویس به Backend متصل شویم:
http://backend:8000این آدرس داخل شبکه Docker قابل استفاده است، اما Next.js که حالا روی سیستم شما اجرا شده، معمولاً نمیتواند از این نام استفاده کند.
در عوض باید پورت Backend روی Host منتشر شده باشد.
برای مثال:
services:
backend:
ports:
- "8000:8000"در این حالت Backend از سیستم شما با آدرس زیر قابل دسترسی است:
http://127.0.0.1:8000قبل از اجرای Next.js بهتر است همین آدرس را در مرورگر یا با ابزارهایی مثل curl بررسی کنید.
برای مثال:
curl http://127.0.0.1:8000
اگر پاسخ Backend را دریافت کردید، ارتباط Host با Backend برقرار است.
مرحله سوم: Next.js را روی سیستم Local اجرا کنید
حالا وارد پوشه Frontend شوید:
cd frontend
اگر Dependencyهای پروژه هنوز روی سیستم نصب نشدهاند:
npm install
یا اگر پروژه دارای package-lock.json است و میخواهید دقیقاً Dependencyهای Lock شده نصب شوند:
npm ci
سپس Environment Variableهای موردنیاز پروژه را تنظیم کنید.
در پروژه نمونه ما:
export DJANGO_PUBLIC_API_URL=http://127.0.0.1:8000export NEXT_PUBLIC_BASE_URL=http://localhost:3000export NEXT_PUBLIC_NEXTJS_API_URL=http://localhost:3000
در نهایت Next.js را اجرا کنید:
npm run dev
حالا Frontend معمولاً از آدرس زیر در دسترس است:
http://localhost:3000ولی Backend همچنان داخل Docker و از طریق آدرس زیر در دسترس Next.js است:
http://127.0.0.1:8000بهتر است متغیرها را داخل .env.local قرار دهیم
اجرای چند دستور export در هر بار شروع پروژه کمی خستهکننده است.
در Next.js میتوانیم تنظیمات مربوط به محیط Local را داخل فایل .env.local قرار دهیم.
برای مثال:
DJANGO_PUBLIC_API_URL=http://127.0.0.1:8000
NEXT_PUBLIC_BASE_URL=http://localhost:3000
NEXT_PUBLIC_NEXTJS_API_URL=http://localhost:3000حالا برای اجرای Frontend کافی است:
cd frontendnpm run dev
البته نام Environment Variableها کاملاً به ساختار پروژه شما بستگی دارد و موارد بالا فقط براساس پروژه نمونه این مقاله هستند.
یک نکته مهم درباره آدرس سرویسها
یکی از اشتباهات رایج بعد از خارج کردن Next.js از Docker این است که آدرسهای داخلی Docker را تغییر ندهیم.
برای مثال ممکن است قبلاً چنین مقداری داشته باشید:
DJANGO_PUBLIC_API_URL=http://backend:8000backend نام یک سرویس در Docker Compose است و معمولاً سرویسهای دیگری که در همان شبکه Docker قرار دارند میتوانند آن را Resolve کنند.
اما Next.js ما دیگر در آن شبکه نیست.
بنابراین باید از پورتی استفاده کنیم که روی Host منتشر شده است:
DJANGO_PUBLIC_API_URL=http://127.0.0.1:8000این یکی از مهمترین تغییرات هنگام اجرای Frontend خارج از Docker است.
اگر از Windows و WSL استفاده میکنید
اگر نمیخواهید Next.js را از Docker خارج کنید، یک راهکار دیگر هم ارزش بررسی دارد.
Docker توصیه میکند در محیط WSL 2 سورس پروژههایی که با Linux Container بهصورت Bind Mount استفاده میشوند، داخل فایلسیستم Linux قرار داشته باشند و نه مسیرهایی مثل /mnt/c.
Docker اعلام میکند عملکرد Bind Mount از فایلسیستم Linux بهتر است و File Change Eventها نیز در این حالت بهتر در اختیار کانتینر قرار میگیرند.
بنابراین این مسیر:
/home/user/projects/my-projectبرای چنین سناریویی معمولاً انتخاب مناسبتری از مسیری شبیه این است:
/mnt/c/Users/user/projects/my-projectاگر با همین تغییر مشکل شما حل شد، شاید اصلاً نیازی به خارج کردن Next.js از Docker نداشته باشید.
مزیت این روش چیست؟
با این ساختار همچنان مزایای Docker را برای بخشهایی که به آن نیاز دارند حفظ میکنیم.
PostgreSQL، Redis، Backend و Celery بدون نیاز به نصب مستقیم روی سیستم اجرا میشوند، اما Next.js مستقیماً به فایلهای پروژه روی سیستم دسترسی دارد.
در نتیجه مسیر Development سادهتر میشود:
ویرایش فایل
↓
Next.js روی سیستم Local
↓
Fast Refresh
↓
مرورگرو برای درخواستهای Backend:
Next.js
↓
127.0.0.1:8000
↓
Docker
↓
Django Backendاین معماری مخصوص Development است و به این معنی نیست که در Production نیز باید Next.js را خارج از Docker اجرا کنید.
آیا همیشه باید Next.js را از Docker خارج کنیم؟
خیر.
اجرای Next.js داخل Docker به خودی خود اشتباه نیست.
Bind Mountها نیز یکی از روشهای استاندارد Docker برای توسعه هستند.
اگر سرعت Development مناسب است، دلیلی ندارد ساختار پروژه را تغییر دهید.
این راهکار بیشتر زمانی مفید است که بررسی کردهاید گلوگاه محیط Development شما اجرای Next.js همراه با فایلهای Bind Mount شده داخل Docker است و اجرای npm run dev مستقیماً روی Host تجربه بسیار سریعتری ایجاد میکند.
همچنین باید در نظر داشته باشید که با اجرای Local، نسخه Node.js نصبشده روی سیستم بهتر است با نسخهای که پروژه یا Dockerfile انتظار دارد هماهنگ باشد. ابزارهایی مثل nvm میتوانند مدیریت نسخه Node.js را سادهتر کنند.
جمعبندی
اگر Next.js را همراه با کل پروژه داخل Docker اجرا میکنید و در زمان Development با کندی Fast Refresh، دیر اعمال شدن تغییرات یا کندی غیرعادی صفحات مواجه هستید، یکی از راهکارهای ساده این است که فقط Frontend را خارج از Docker اجرا کنید.
در سناریوی نمونه ما ابتدا سرویسهای موردنیاز را اجرا کردیم:
docker compose --env-file .env.prod -f docker-compose.dev.yml up -d postgres redis backenddocker compose --env-file .env.prod -f docker-compose.dev.yml up -d celery_worker
سپس Next.js را روی سیستم Local اجرا کردیم:
cd frontendexport DJANGO_PUBLIC_API_URL=http://127.0.0.1:8000export NEXT_PUBLIC_BASE_URL=http://localhost:3000export NEXT_PUBLIC_NEXTJS_API_URL=http://localhost:3000npm run dev
به این ترتیب سرویسهایی که اجرای آنها در Docker برای ما مفید است همچنان Containerized باقی میمانند، ولی Next.js مستقیماً روی سیستم اجرا میشود.
این کار بهخصوص زمانی مفید است که مشکل اصلی Development شما سربار File Sharing و Bind Mount باشد.
سوالات متداول
آیا برای این روش باید Docker را کنار بگذاریم؟
خیر. فقط Next.js را روی سیستم Local اجرا میکنیم و سرویسهایی مثل PostgreSQL، Redis و Backend همچنان داخل Docker باقی میمانند.
چرا backend:8000 دیگر کار نمیکند؟
چون backend معمولاً نام سرویس داخل شبکه Docker است. وقتی Next.js خارج از Docker اجرا میشود باید از پورتی که Backend روی Host منتشر کرده استفاده کنید؛ برای مثال:
http://127.0.0.1:8000آیا این روش برای Production هم مناسب است؟
این مقاله درباره بهبود تجربه Development است. معماری Production مسئله جداگانهای است و میتوانید همچنان Next.js را در Production داخل Docker اجرا کنید.
آیا خارج کردن Next.js از Docker همیشه سرعت را بیشتر میکند؟
نه لزوماً. ابتدا بهتر است مشخص کنید مشکل واقعاً از File Sharing، Bind Mount یا File Watching است. اگر اجرای Local تفاوت محسوسی ندارد، احتمالاً گلوگاه پروژه جای دیگری است.














