Nix আর direnv দিয়ে Reproducible Dev Environment

সেই সকাল এখনও মনে আছে যখন New Project-এ Join করেছিলাম আর তিন ঘন্টা Node.js Versions-এর সাথে Fight করতে হয়েছিল। README বলেছিল "Requires Node 18," কিন্তু System-এ 20 ছিল, আর nvm Moody ছিল। Environment কাজ করতে যখন Time নিলো, ততক্ষণে Forget করেছিলাম কেন Contribute করতে চেয়েছিলাম। সেই মুহূর্তে Realize করেছিলাম: Nix আর direnv development environment সেটআপ করা ছাড়া এই "Works on my machine" পেইন থেকে মুক্তি নেই।

"Just Install It"-এর Chaos

Traditional Development Setup Familiar Pattern Follow করে। Repo Clone করো, README পড়ো, Right Language Version Install করো, Dependencies Install করো, বুঝতে পারো Specific Database Version দরকার, সেটা Install করো, Environment Variables Configure করো, Project-এর Older CLI Tool Version দরকার Discover করো, Package Manager-এর সাথে Fight করো, আর Eventually — Lucky হলে — Application Run করো।

Problems Multiply হয় যখন Projects-এর মধ্যে Switch করো। Node 18 Project তোমার Node 20 Side Project-এর সাথে Conflict করে। Python 3.9 Dependency তোমার System Tools Break করে। গতকাল কাজ করা Database Version আজ Production-এর সাথে Match করে না। আর New Team Member Onboard করাও — তাদের দেখতে হবে Same Three-hour Ritual-এর মধ্য দিয়ে।

যা দরকার ছিল তা হলো Environment Declare করার Way: "This project needs Node 18.17, PostgreSQL 15, Redis 7, আর এই Specific CLI Tools।" আর চাইলাম এটা Just Work করুক যখন Project Directory-এ Enter করি।

Nix আর direnv development environment কেন দরকার?

Nix প্রথম Problem Solve করে। এটা এমন Package Manager যেটা Any Version of Any Package Side-by-side Install করতে পারে Conflicts ছাড়া। direnv দ্বিতীয় Problem Solve করে — এটা Automatic Activate করে Environment Variables আর Tools যখন Directory-এ Enter করো।

Together, তারা কিছু Powerful Create করে: Development Environment যেটা Automatic Activate হয় যখন cd দিয়ে Project-এ যাও আর Disappear হয় যখন Leave করো। No Manual Switching। No Global System Pollution। Just Clean, Isolated, Reproducible Environments।

Actually কিভাবে কাজ করে

যখন Project Directory-এ Enter করি, direnv .envrc File Detect করে আর Load করে Environment যেটা Defined আছে। সেই File Nix-কে বলে Build করতে Shell Exactly Packages দিয়ে যেগুলো Project-এর flake.nix-এ Specified। Directory Leave করলে direnv Unload করে Everything। System Pristine থাকে।

Go Project-এর Typical Setup দেখি:

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            go_1_22
            golangci-lint
            gotools
            gopls

            # Project-specific Tools
            postgresql_16
            redis
            jq

            # এই Versions `flake.lock` দিয়ে Pinned
            # Team-এর Everyone Exact Same Versions পায়
          ];

          shellHook = ''
            echo "Go $(go version)"
            echo "PostgreSQL $(pg_config --version)"

            # Local Project Paths Setup করো
            export PGDATA="$PWD/.postgres"
            export REDIS_DATA="$PWD/.redis"
          '';
        };
      });
}

আর .envrc File যেটা Activate করে:

# .envrc
use flake

That's it। cd দিয়ে Project-এ গেলে direnv Nix Flake Load করে, আর Suddenly Go 1.22, Exact Linter Version, PostgreSQL 16, Redis, আর সব Configured Tools থাকে। cd দিয়ে বের হলে Gone। System Shell Untouched থাকে।

যে Features Matter করে

flake.lock File প্রতিটা Dependency-কে Exact Commit-এ Pin করে। Teammate Run করলে Bit-for-bit Identical Versions পায় প্রতিটা Tool-এর। No "works on my machine" কারণ Everyone Literally Same Machine Defined in Code।

Dependencies Update করতে চাও? nix flake update Lock File Regenerate করে। Exactly কী Change হলো জানতে চাও? git diff flake.lock প্রতিটা Package Version Change দেখায়। Roll Back করতে চাও? git checkout Previous Lock File। Development Environment-এর জন্য Version Control।

True Isolation

প্রতিটা Project নিজের Namespace of Packages পায়। একটা Project Node 18.17-এর উপর Specific npm Version-এ, আরেকটা Node 20-এর উপর Different npm-এ, আরেকটা Ancient Node 16-এ Legacy Maintenance-এর জন্য। Never Interfere with each other বা System Packages।

Environment Variables-এর জন্যও Extend হয়। Flake-এর shellHook Project-specific Paths আর Configuration Set করে। Directory Leave করলে Those Variables Disappear। Accidentally Production Commands Development Credentials দিয়ে Run করার Fear নেই Environment Files Switch করতে ভুলে।

Instant Onboarding

New Team Member Join করে? তারা Nix Install করে, Repo Clone করে, cd দিয়ে Directory-এ যায়, আর direnv allow Run করে। That's it। Entire Environment Automatic Build হয়। Same Go Version, Same Linter, Same Database, Same Everything। Onboarding Time Hours থেকে Minutes-এ Drop করে।

Real-World Project Examples

Different Projects Need Different Setups। Common Scenarios কিভাবে Structure করি:

Database সহ Web Project

{
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            nodejs_20
            pnpm
            postgresql_16
            redis
          ];

          shellHook = ''
            # Services Automatic Start করো যদি Already Running না হয়
            if [ ! -d "$PGDATA" ]; then
              initdb --auth=trust --no-locale --encoding=UTF8
            fi
            pg_ctl start -l log/postgres.log 2>/dev/null || true
            redis-server --daemonize yes --dir "$PWD/.redis" 2>/dev/null || true

            echo "Node $(node --version)"
            echo "Database ready on localhost:5432"
          '';
        };
      });
}

এখন Directory Enter করলে Automatic PostgreSQL আর Redis Start হয় (Already Running না থাকলে) আর Leave করলে Stop। Entire Development Stack Self-contained।

Multi-Language Project

কখনও এক Project-এ Multiple Ecosystem দরকার:

{
  devShells.default = pkgs.mkShell {
    buildInputs = with pkgs; [
      # Backend
      go_1_22

      # Frontend
      nodejs_20
      pnpm

      # Infrastructure
      terraform
      kubectl
      awscli2

      # Common Tools
      jq
      yq
      git
    ];
  };
}

Team-এর Everyone Exact Same Terraform Version Use করে। "Upgrade your CLI" Slack Messages নেই যখন কেউ Infrastructure Code Update করে।

Honest Trade-offs

এই Setup কোনোভাবেই Free না। First Time কেউ Nix Environment Run করে, Build করতে কিছু সময় লাগতে পারে — বিশেষ করে Binary Caches Miss করলে। সেই "Instant Onboarding" হয়ে যায় "Wait 20 minutes while Nix Compiles Everything।" Subsequent Runs Fast থাকে, Caching-এর জন্য, কিন্তু সেই Initial Build এর পেইন একদম সহ্য করার মতো না।

আর Nix এর এরর মেসেজগুলো? জঘন্য। মনে হয় যেন কোনো এলিয়েন ল্যাঙ্গুয়েজ পড়তেছি। মাঝে মাঝে ছোট একটা টাইপো ঠিক করতে গিয়ে ঘন্টার পর ঘন্টা চলে যায়। Nix-এর নিজের Language, নিজের Concepts, আর Documentation যেটা Often Assume করে তুমি Already সেই Concepts বুঝো। Junior Developer-কে Nix শেখানো তাদের First Line of Code লেখার আগে Probably Overkill। Simple Projects-এর জন্য Overhead Worth না হতে পারে।

Docker Compose Similar Problems Solve করে আর Better Fit হতে পারে যদি Team Already Comfortable থাকে। Trade-off হলো Docker-এর Overhead আর Commands Container-এর ভিতর Run করার দরকার Rather than Native Shell। Nix Container-like Isolation দেয় Native Performance-এর সাথে।

কখন এটা Shine করে

Nix + direnv Reach করি যখন:

  • Multiple Projects Same Tool-এর Different Versions চায়
  • Team Onboarding Painful আর Inconsistent
  • "Works on my machine" Regularly হয়
  • CI আর Local Environment Exactly Match করতে চাই
  • Complex Development Stacks দরকার (Multiple Databases, Message Queues, etc.)

Reach করি না যখন:

  • এটা Quick One-off Script
  • Team Development-এ New আর Already Overwhelmed
  • Project শুধু একটা Common Tool চায় (যেমন শুধু Node.js)
  • Everyone Already তাদের Setup-এ Happy

Getting Started

নিজে Try করতে চাইলে:

  1. Nix Install করো Flakes Enable করে: Determinate Systems installer Easy বানায়
  2. direnv Install করো: nix profile install nixpkgs#direnv (Ironically) বা System Package Manager Use করো
  3. direnv-কে Shell-এ Hook করো: direnv hook bash (বা zsh, fish) Shell Config-এ
  4. Project Root-এ flake.nix Create করো (উপরের Examples থেকে Start করো)
  5. .envrc Create করো শুধু use flake দিয়ে
  6. Project Directory-এ direnv allow Run করো

That's it। Environment Automatic Activate হয়।

Resources

Meta Description: Nix আর direnv development environment সেটআপ করে আপনার প্রোজেক্টকে Isolated এবং Reproducible বানান। "Works on my machine" ঝামেলার চিরস্থায়ী সমাধান।

Asaduzzaman Pavel

About the Author

Asaduzzaman Pavel is a Software Engineer who actually enjoys the friction of a well-architected system. He has over 15 years of experience building high-performance backends and infrastructure that can actually handle the real-world chaos of scale.

Currently looking for new opportunities to build something amazing.