از ۱۹۹۰ تا ۲۰۲۵: تجربه آشنایی و استفاده از Nixpacks
آرمین هوشمند
طبق معمول، بر اساس نیازی که به وجود اومد؛ مسیری باز شد تا با Nixpacks آشنا بشم. استفادهی من برای دیپلوی یک پروژه لاراولی بود و چون تجربه واقعاً جذابی شد، تصمیم گرفتم با شما هم به اشتراک بذارمش.

جهنم وابستگی
تصور کن اوایل دههی ۹۰ پشت کامپیوترت نشستی و میخوای دو تا برنامه ساده نصب کنی.
همهچیز خوب پیش میره تا وقتی میفهمی اولی فقط با نسخهی قدیمی یه کتابخونه کار میکنه و دومی لجبازانه نسخهی جدید رو میخواد.
اینجاست که کابوس شروع میشه: یا یکی از برنامهها از کار میفته، یا کل سیستم قاطی میکنه.
همون روزها بود که جملهی معروف «روی سیستم من کار میکنه» بین برنامهنویسها به یه طنز تلخ تبدیل شد.
تولد Nix
اوایل دههی ۲۰۰۰ هنوز بوی «جهنم وابستگی» همهجا بود. برنامهنویسها مدام گیر تضاد نسخهها میافتادن و هر بار نصب یه نرمافزار میتونست یه ریسک بزرگ باشه.
توی همین فضا، سال ۲۰۰۳ یه دانشجوی دکترا به اسم Eelco Dolstra نشست پشت میز پایاننامهاش و پرسید:
«چی میشد اگه میتونستیم بیلد نرم افزار رو هم مثل توابع ریاضی قابل پیشبینی و مشخص کنیم؟»
یعنی چی؟ یعنی وقتی ورودی ثابت باشه، خروجی هم همیشه ثابت بمونه؛ بدون غافلگیری، بدون قاطیپاطی شدن.
برای رسیدن به این هدف، Dolstra چند اصل رو پیشنهاد داد:
- هر پکیج مسیر مستقل خودش رو داشته باشه.
- تعریفها Declarative باشن، نه دستوری و مبهم.
- و نتیجه همیشه قابلبازتولید باشه.
این ایده خیلی زود تبدیل شد به پروژهای به اسم Nix.
از دل Nix کمکم یه اکوسیستم کامل بیرون اومد: NixOS به عنوان سیستمعامل، Hydra برای CI، و بعدها Flakes برای مدیریت تمیز و ماژولار کانفیگها.
از همونجا بود که مفهوم Reproducible Builds دیگه فقط یه رویا نبود، بلکه به یکی از جدیترین حرکتهای دنیای نرمافزار تبدیل شد.
اصول Nix در چند خط (با مثال)
-
Pure builds ← خروجی فقط به ورودیها بستگی داره.
مثلا اگه بیلد پروژهت رو با PHP 8.2 تعریف کردی، همیشه 8.2 تحویل میگیری؛ نه بسته به حال و هوای سیستم. -
مسیر یکتای پکیجها ← هر نسخه جای مخصوص به خودش رو داره.
یعنی میتونی همزمان PHP 8.2 و PHP 8.3 رو داشته باشی، بدون اینکه همدیگه رو خراب کنن. (برخلاف apt که یکی باید قربانی بشه!) -
Declarative ← فقط میگی چی میخوای، نه اینکه چطور نصب بشه.
مثلا میگی: «من یه PHP 8.2 با ext-redis لازم دارم»؛ Nix خودش مسیر و وابستگیها رو حل میکنه. -
Reproducibility ← امروز یا یه ماه دیگه همون نتیجه رو میگیری.
مثلا اگه امروز توی اوبونتوapt install php
بزنی شاید PHP 8.2 نصب شه، فردا دوستت بزنه بشه 8.3. ولی توی Nix همیشه دقیقاً همون نسخهای نصب میشه که تعریف کردی.
ورود Nixpacks
سالها سرویسهایی مثل Heroku و Dokku با buildpackها دنیا رو سادهتر کردن. کافی بود کد رو پوش کنی، یه دکمه بزنی و برنامهت بالا بیاد.
اما مشکل اینجا بود: این سادگی همیشه قابل اعتماد نبود. یه روز همهچی درست کار میکرد، فرداش یه آپدیت مخفی میتونست نتیجهی بیلد رو عوض کنه.
از اون طرف، تیمهای نرمافزاری دنبال چیزی بودن که مطمئن باشن امروز و یک ماه دیگه همون خروجی رو میگیرن.
یعنی چیزی که هم سادگی PaaS رو داشته باشه، هم قابلیت بازتولید (Reproducibility) رو.
اینجا بود که Nixpacks وارد شد: یه buildpack مدرن که روی Nix سوار شده.
نتیجه؟ دیپلویی که هم به اندازهی Heroku سرراست و بیدردسره، هم مثل دنیای Nix قابل پیشبینی و تکرارپذیره.
Nixpacks چطوری کار میکنه؟
ماجرا خیلی سادهست: Nixpacks کدت رو میخونه، تشخیص میده پروژهت به چه زبان و ابزارهایی نیاز داره و بعد برات یه ایمیج استاندارد (OCI) میسازه که روی هر جایی (از سرور خودت گرفته تا Kubernetes و PaaSها) قابل اجراست.
ویژگیهاش
- تقریباً zero-config ← معمولاً بدون نوشتن هیچ تنظیم اضافهای کار میکنه.
- کاملاً قابلشخصیسازی ← هر فاز از بیلد رو بخوای میتونی override کنی.
- توسعهپذیر ← اگه Nix یا Docker بلدی، میتونی تا جایی که بخوای دستکاری و گسترش بدی.
نکته مهم: Nixpacks قرار نیست جایگزین Dockerfile بشه. بیشتر مثل یه مسیر سریعتر و تمیزتره برای وقتی که میخوای با کمترین تنظیمات، یه دیپلوی قابل پیشبینی و بدون دردسر داشته باشی.
پشت پرد: از پلن تا بیلد
مرحله اول: Plan
سورس رو آنالیز میکنه و یه build plan میسازه. توی این پلن مشخصه چه پکیجها و دستورات لازمان و چه providerهایی وارد میشن.
مرحله دوم: Build
با همون پلن، یه ایمیج OCI میسازه (معمولاً با Docker BuildKit). نتیجه قابل پیشبینی و reproducible درمیاد.
فازهایی که Nixpacks اجرا میکنه به زبان ساده
- Setup: آمادهسازی محیط و ابزارها.
- Install: نصب وابستگیها (composer, npm, …).
- Build: خروجی نهایی اپ.
- Start: دستور شروع کانتینر.
TOML و nixpacks.toml
TOML یه فرمت ساده و خواناست. اسمش هم مخفف Tom's Obvious, Minimal Language هست
ساختار کلی nixpacks.toml
:
[variables]
برای متغیرها[providers]
برای فعال/غیرفعال کردن providerها[phases.*]
برای فازها[start]
برای فرمان شروع[staticAssets]
برای فایلهایی که مستقیم توی ایمیج میرن
یه مثال مینیمال:
[variables]NIXPACKS_NODE_VERSION = "22" [phases.setup]nixPkgs = ["..."] [phases.install]cmds = ["composer install --no-dev --no-interaction"] [start]cmd = "php artisan serve --host=0.0.0.0 --port=8080"
شروع سریع (دو فرمان)
Nixpacks رو میتونی با دو خط ساده تست کنی:
nixpacks plan .nixpacks build . --name my-app
تجربهی من با لاراول
به نظرم تجربهای نسبتاً سرراست و حتی هیجانانگیز بود. واقعا غافلگیر شدم که با کمترین تنظیمات تونستم یه پروژه لاراولی رو بالا بیارم. هیچ خبری از Dockerfileهای شلوغ و طولانی، dependency mismatch یا دردسرهای معمول نبود.
سادگی کار اونقدر بالاست که حس میکنی داری یه پروژه روی لوکال ران میکنی، نه روی یه سرور واقعی. نکتهی جالب اینه که این تجربه اصلاً به لاراول محدود نمیشه—میتونی با همین رویکرد تقریبا هر پروژه دیگهای رو دیپلوی کنی؛ از Node.js گرفته تا Go، Python یا حتی یه میکروسرویس کوچیک.
برای خودم یه لحظه مقایسه کردم با دفعاتی که برای دیپلوی، ساعتها درگیر نوشتن و دیباگ کردن Dockerfile بودم. اینجا همهچی مثل یه «جادوی تمیز» اتفاق میافته:
- سریع
- تکرارپذیر
- و بدون اینکه ذهنتو با جزئیات فرسایشی مشغول کنه
به جرئت میتونم بگم بعد از این تجربه، دیگه اولین انتخابم برای هر پروژهی جدید همین Nixpacks خواهد بود.
کی باید Nixpacks رو انتخاب کنیم؟
- وقتی reproducibility برات مهمه.
- وقتی نمیخوای وقتت رو با Dockerfileهای طولانی تلف کنی.
- وقتی کنترل جزئی روی لایههای Docker لازم نداری.
جمعبندی
برای من، Nixpacks یعنی: دیپلوی تمیز، ساده و تکرارپذیر — چه امروز، چه فردا. اگر بخوام خلاصه کنم، Nixpacks برای من مثل ترکیب راحتی Heroku و قدرت Nix بود؛ چیزی که باعث شد دفعهی بعدی برای دیپلوی، بدون تردید سمتش برم.
سورس کامل روی گیتهاب: https://github.com/panicdevs/laravel-nixpacks