Bun-এর Rust রিলিখন: ১১ দিন, ৬,৭৭৮ কমিট, এবং আসলে কী বদলেছে
Bun-এর টিম মে ২০২৬-এ একটা অস্বাভাবিক জিনিস শিপ করেছে: তারা রানটাইমের পুরো নেটিভ কোরটাকে একটা Rust পোর্ট দিয়ে বদলে দিয়েছে, আর সেটাও ১১ দিনে।
ঘোষণার ওপরে যা লেখা আছে তা টোনটা সেট করে দেয়। Bun-কে ডিসেম্বর ২০২৫-এ Anthropic কিনে নিয়েছিল। Bun-এর স্রষ্টা Jarred Sumner কাজের বেশিরভাগটাই Claude-এর একটা প্রি-রিলিজ ভার্সন — যাকে তারা “Mythos-class model” বলে, Fable 5 — দিয়ে করেছেন। এটা কোনো থট এক্সপেরিমেন্ট নয়। প্রথম Rust ভার্সন, Bun v1.4.0, এখন canary-তে আছে।
কাঁচা নাম্বারগুলো এইরকম:
- ৫৩৫,৪৯৬ লাইন Zig (কমেন্ট বাদ দিয়ে) একটা Rust কোডবেস-এ পরিণত হয়েছে
- ৩ মে থেকে ১৪ মে-র মধ্যে ৬,৭৭৮ কমিট
- ১,৪৪৮টা
.zigফাইল মেশিনি ভাবে.rs-এ পোর্ট করা হয়েছে - API-তে খরচ প্রায় $165,000 (৫.৯B আনক্যাশড ইনপুট টোকেন, ৬৯০M আউটপুট টোকেন)
- পিক-এ: ৪টে ওয়ার্কট্রি-তে একসাথে ৬৪টে Claudes চলছিল

Bun শুরু থেকেই ছিল একটা Zig-এর দাও
Bun শুরু হয়েছিল esbuild-এর JS/TS ট্রান্সপাইলারকে Go থেকে Zig-এ লাইন-বাই-লাইন পোর্ট করার মাধ্যমে। Sumner ১৬ এপ্রিল ২০২১-এ Hacker News-এ Zig-এর সিঙ্গেল-পেজ ল্যাঙ্গুয়েজ রেফারেন্স দেখার পর তাঁর প্রথম Zig লাইন লিখেছিলেন। প্রথম ভার্সনটা — ট্রান্সপাইলার, মিনিফায়ার, বান্ডলার, npm-কম্প্যাটিবল প্যাকেজ ম্যানেজার, Jest-এর মতো টেস্ট রানার, Node.js API সারফেস — একজন লোক এক বছরে, Oakland-এর একটা ছোট অ্যাপার্টমেন্টে, তখন লিখেছিলেন যখন এই কাজের জন্য LLM উপযোগী ছিল না।
সেই দাও কাজে লেগেছে। Bun-এর CLI-এর এখন ২২ মিলিয়নের বেশি মান्थলি ডাউনলোড হয়। Claude Code আর OpenCode এটাকে তাদের রানটাইম হিসেবে ব্যবহার করে। Vercel, Railway আর DigitalOcean ফার্স্ট-পার্টি সাপোর্ট শিপ করে।
স্কোপটাই ছিল সমস্যাও।
ঋণ: GC মেমোরির পাশে ম্যানুয়াল মেমোরি
JavaScript গারবেজ-কলেক্টেড। Bun-এর ভেতরে JavaScriptCore (Safari-এর ইঞ্জিন) আছে, সাথে C/C++ লাইব্রেরির একটা স্তূপ: uWebSockets, BoringSSL, SQLite, lsquic। Zig, C-এর মতো, তোমার হয়ে মেমোরি ম্যানেজ করে না। Bun-এর কাজ হলো একটা GC-করা ল্যাঙ্গুয়েজ আর ম্যানুয়ালি-ম্যানেজড নেটিভ কোডের মাঝখানে দাঁড়ানো, আর সেই বাউন্ডারিটাই ছিল যেখানে তাদের সবচেয়ে খারাপ বাগগুলো ছিল।
ঘোষণায় v1.3.14-এ একাই তারা যা ফিক্স করেছে তার একটা নমুনা লিস্ট আছে: node:zlib-এ একটা heap-use-after-free, রি-এন্ট্রান্ট কলব্যাক থেকে node:http2-তে use-after-free, UDPSocket.sendMany-তে out-of-bounds রাইট, প্রতিটা tls.connect-এ একটা মেমোরি লিক, CSS পার্সারে একটা double-free। লিস্ট এগোতেই থাকে, আর এটা টেকনিক্যাল।
Sumner স্পষ্ট করে বলেছেন এটা Zig-এর দোষ নয়। “We wouldn’t have gotten this far if not for Zig, and I’ll always be grateful.” (Zig ছাড়া আমরা এতদূর আসতে পারতাম না, আর আমি সবসময় কৃতজ্ঞ থাকব।) আসল সমস্যাটা স্ট্রাকচারাল: GC বাউন্ডারির ওপর দিয়ে লাইফটাইম হ্যান্ডেল করা যেকোনো ল্যাঙ্গুয়েজেই কঠিন যেটা এর জন্য ডিজাইন করা নেই, আর Zig-এর উত্তর — প্রতিটা কল সাইটে এক্সপ্লিসিট defer — রেয়ারলি-রিচড এরর পাথগুলোতে ভুল হওয়া সহজ।
তিনি C++-এর কথাও ভেবেছিলেন। Bun-এর প্রায় ২০% ইতিমধ্যে C++-এ আছে, আর আরও যোগ করলে কনস্ট্রাক্টর আর ডেস্ট্রাক্টর পাওয়া যেত। কিন্তু তবুও কোড রিভিউয়ের মাধ্যমে চাপিয়ে দেওয়া স্টাইল গাইডের ওপরেই নির্ভর করতে হতো, আর মেমোরি করাপশন তবুও ঘটত।
Rust-এর পিচটা আলাদা: সেফ Rust-এ, use-after-free, double-free, আর “ফ্রি করতে ভুলে গেছি” এগুলো কম্পাইলার এরর। বোরো চেকার আর Drop একটা স্টাইল-গাইড প্রব্লেমকে টাইপ-সিস্টেম প্রব্লেমে পাল্টে দেয়।
কৌশল: ট্রান্সপাইল করো, রি-ডিজাইন নয়
রিলিখনের খারাপ নাম আছে, আর কারণটা জায়েজ। ৫৩৫K লাইনের স্ক্র্যাচ-থেকে রিলিখন ফিচার আর ফিক্সগুলোকে এক বছরের জন্য ফ্রিজ করে দিত। Bun যে শেপটা বেছে নিয়েছিল সেটা ছিল একটা মেশিনি পোর্ট: একই আর্কিটেকচার, একই পারফরম্যান্স টার্গেট, একই ফিচার, একই টেস্ট স্যুট — শুধু Rust-এ।
পুরো কাজটাকে দুটো সিদ্ধান্ত ড্রাইভ করেছিল:
১. একসাথে সব, ইনক্রিমেন্টাল নয়। esbuild-কে Zig-এ পোর্ট করার Sumner-এর অভিজ্ঞতা বলেছিল যে ইনক্রিমেন্টাল রিলিখনগুলো অস্থায়ী স্ক্যাফোল্ডিং রেখে যায় যা সাহায্যের চেয়ে বেশি ক্ষতি করে। ২. এটাকে ট্রান্সপাইল্ড দেখতে দাও। লক্ষ্য ছিল এমন Rust লেখা যা তার নিজের Zig-এর মতো পড়ে, যাতে v1.4 শিপ হওয়ার পরে এটাকে idiomatic Rust-এ রি-ফ্যাক্টর করা যায়।
একদম জরুরি ব্যাপারটা হলো, Bun-এর টেস্ট স্যুট TypeScript-এ লেখা, তাই রানটাইমটা কোন ল্যাঙ্গুয়েজে ইমপ্লিমেন্ট করা হয়েছে তা নিয়ে তার কিছু যায় আসে না। এটাই “সব টেস্ট গ্রিন”কে ডান-এর ডেফিনিশন বানাতে দিয়েছিল।
প্রস্তুতিটা ছোট ছিল কিন্তু ইচ্ছাকৃত। কোড লেখার আগে Sumner Claude-এর সাথে প্রায় ৩ ঘণ্টা Zig প্যাটার্নগুলোকে Rust-এর সাথে ম্যাপ করতে কাটিয়েছিলেন; সেই কথোপকথন PORTING.md হয়ে গিয়েছিল (এটা পরে Hacker News-এ উঠেছিল)। দ্বিতীয় একটা পাস পুরো কোডবেস জুড়ে প্রতিটা struct ফিল্ড-এর সঠিক Rust লাইফটাইমের এনালিসিস করেছিল আর সেগুলোকে LIFETIMES.tsv-এ সিরিয়ালাইজ করেছিল। একটা লাইনও পোর্ট হওয়ার আগে দুটো ডকুমেন্টই অ্যাডভারসেরিয়াল রিভিউ দিয়ে গেছে।
যা নড়েনি: JavaScriptCore আর এম্বেডেড C/C++ লাইব্রেরিগুলো। রিলিখনটা ছিল নেটিভ গ্লু আর Bun-স্পেসিফিক কোডের, JS ইঞ্জিনের নয়।
এক্সিকিউশন: ৬৪ Claudes, ১১ দিন
পোর্টটা টানা, ১১ দিন ধরে, Claude Code-এ প্রায় ৫০টা “ডায়নামিক ওয়ার্কফ্লো” হিসেবে চলেছে। প্রতিটা ওয়ার্কফ্লো ছিল একটা লুপ: একটা টাস্ক নাও, কোড বানাও, রিভিউ করাও, ফিডব্যাক লাগাও।
রিভিউ মডেলটাই আসলে আকর্ষণীয় অংশ। প্রতিটা ইমপ্লিমেন্টারের জন্য ছিল দুটো বা তার বেশি অ্যাডভারসেরিয়ল রিভিউয়ার — আলাদা Claude সেশন যাদের বলা হয়েছিল কোডটা ভুল ধরে নিতে আর ফেল হওয়ার প্রতিটা কারণ বের করতে। ইমপ্লিমেন্টার কখনও রিভিউ করে না; রিভিউয়ার কখনও ইমপ্লিমেন্ট করে না। ঘোষণা এটাকে মানুষের রিভিউয়ের নকল বলে দেখায়: লেখক মার্জ করতে চায়, তাই চেক করে এক অন্য পক্ষ।
কয়েকটা মেকানিক্স আলাদা করে তোলার মতো:
- আগে ট্রায়াল রান। তারা সব ১,৪৪৮ ফাইল কমিট করার আগে ৩টে ফাইল পোর্ট করেছিল।
- ওয়ার্কট্রি শার্ডিং। শুরুর দিকের রানগুলোতে Claudes গুলো
git stashআরgit resetদিয়ে একে অন্যকে মাড়িয়ে যাচ্ছিল। ফিক্স: ৪টে ওয়ার্কট্রি, প্রতিটাতে ১৬ Claudes, আর একটা নিয়ম যে টাস্কের মাঝখানে কখনও git বা cargo চালাবে না। - কম্পাইলার এররকে ওয়ার্ক কিউ-এর মতো।
cargo checkপ্রায় ১৬,০০০ এরর একটা ফাইলে ডাম্প করেছিল, crate অনুযায়ী গ্রুপ করা, আর ৬৪ Claudes একটু একটু করে কেটেছে — ৪ ওয়ার্কট্রি-তে ১৬টা fix/review/apply লুপ। - সাইক্লিক্যাল ডিপেন্ডেন্সি। Zig আসলে একটা কম্পাইলেশন ইউনিট ছিল; Rust-এর ~১০০টা crate লাগত। সাইকেলগুলো আলাদা করতে গেলে ওই ১৬,০০০ এররের বেশিরভাগ বেরিয়ে এসেছিল।
- আইসোলেশন। যে স্ট্রেস টেস্টগুলো TCP সকেট শেষ করে দেয় বা ~১০k প্রসেস স্পন করে, সেগুলো
systemd-runcgroup-এর নিচে চলেছিল। মেশিন তবুও ডিস্ক শেষ করে ফেলেছিল আর কয়েকবার ক্র্যাশ করেছিল।
timeline
title Bun-এর ১১-দিনের Zig → Rust রিলিখন (মে ২০২৬)
2026-05-03 : পোর্ট ব্রাঞ্চ খোলা হয়েছে (PR #30412)
2026-05-04 : প্রথম ১০০-ফাইল ড্রাফট ব্যাচ
2026-05-06 : ~১৬,০০০ কম্পাইলার এরর, ৬৪ Claudes
2026-05-08 : প্রথম CI রান (৯৭২ ফেল ফাইল)
2026-05-09 : Linux x64 সবুজ হয়েছে
2026-05-11 : Windows সবুজ (শেষ প্ল্যাটফর্ম)
2026-05-14 : সব ৬ প্ল্যাটফর্ম সবুজ, মার্জ করা হয়েছে
নাম্বার দিয়ে: পিক-এ এক মিনিটে ১,৩০০ লাইন কোড, সবচেয়ে ব্যস্ত ঘণ্টায় ৬৯৫ কমিট (৬ মে), সবচেয়ে ব্যস্ত এক মিনিটে ৫৮ কমিট। ল্যান্ড হওয়ার আগে প্রতিটা কমিট দুটো অ্যাডভারসেরিয়ল রিভিউয়ার দিয়ে রিভিউ হয়েছিল। শেষ ডিফটা ছিল +১,০০৯,২৭২ লাইন। কোনো টেস্ট স্কিপ বা ডিলিট করা হয়নি।
CI-ই ছিল যেখানে এটা আসল হয়ে উঠেছিল। প্রথম রানের দুই দিন পর, ফেল টেস্ট ফাইল ৯৭২ থেকে কমে ২৩-এ দাঁড়িয়েছিল। দেড় দিন পর Linux পুরোপুরি গ্রিন হয়ে গিয়েছিল। Windows শেষ হয়েছিল ১১ মে-তে; সব ছয়টে প্ল্যাটফর্ম বিল্ড #৫৪২০২-তে, ১৪ মে-তে গ্রিন ছিল।
Rust আসলে কী কিনেছে
স্টেটেড গোল ছিল স্টেবিলিটি, আর পোস্টটা তা হার্ড নাম্বার দিয়ে ব্যাক করে।
বাগ। Bun v1.4.0 v1.3.14-এ রিপ্রোডিউস হওয়া ১২৮টা বাগ ফিক্স করে।
মেমোরি। Drop প্রতিটা কল সাইটের defer-কে রিপ্লেস করেছে। পোস্টের উদাহরণ: একই প্রোসেসে একই ৬০-মডিউল প্রজেক্ট ২,০০০ বার বান্ডেল করা। v1.3.14-এ প্রতিটা বিল্ড ~৩ MB চিরকালের জন্য লিক করে; v1.4.0-এ মেমোরি লেভেল অফ হয়ে যায়।
| Builds | v1.3.14 | v1.4.0 |
|---|---|---|
| 500 | 1,914 MB | 526 MB |
| 1,000 | 3,506 MB | 586 MB |
| 1,500 | 5,097 MB | 608 MB |
| 2,000 | 6,745 MB | 609 MB |
Zig-এ এটা ফিক্স করার একটা আগের চেষ্টা কখনও মার্জ হয়নি, Sumner লিখেছেন, কারণ Drop-এর সমকক্ষ না থাকায় কনফিডেন্ট হওয়া কঠিন ছিল।
বাইনারি সাইজ। শুধু Rust রিলিখনই ৩.৮ MB (Windows), ৫.৫ MB (macOS), ৬.৮ MB (Linux) কেটেছে — বেশিরভাগই এক্সেসিভ Zig comptime সরিয়ে। তারপর লিংকার ওয়ার্ক (identical code folding, ICU ডেটা ট্রিম করা) মোট শ্রিংকেজকে Linux আর Windows-এ ~২০% পর্যন্ত নামিয়ে এনেছে।
| Version | Platform | Size |
|---|---|---|
| v1.4.0 | Windows | 76 MB |
| v1.3.14 | Windows | 94 MB |
| v1.4.0 | Linux | 70 MB |
| v1.3.14 | Linux | 88 MB |
স্পিড। C/C++ আর Rust-এর মাঝে ক্রস-ল্যাঙ্গুয়েজ LTO কম্পাইলারকে ল্যাঙ্গুয়েজ বাউন্ডারির ওপর দিয়ে ইনলাইন করতে দেয়। Bun ২–৫% গেন মেপেছে:
Bun.serve: 169.6k → 177.7k req/s (+4.8%)express: 64.5k → 66.6k (+3.2%)next build: 13.62s → 13.03s (+4.5%)tsc -b --force: 0.94s → 0.89s (+4.7%)
Prisma তাদের Compute পাবলিক বিটা Rust রিলিখনের ওপর নিয়ে গেছে। Alexey Orlenko: “We ran into memory leaks and a connection pool that couldn’t recover after a VM was paused and resumed. When the Rust rewrite appeared, we tested it against the same failure modes. It handled them perfectly.” (আমাদের মেমোরি লিক আর একটা কানেকশন পুল-এর সমস্যা হয়েছিল যেটা VM পজ আর রিজিউম হওয়ার পর রিকভার করতে পারছিল না। যখন Rust রিলিখন এলো, আমরা এটাকে একই ফেল্যোর মোডগুলোর বিপক্ষে টেস্ট করলাম। এটা সেগুলো পারফেক্টলি হ্যান্ডেল করেছে।)
Claude Code v2.1.181 (১৭ জুন) আর তার পরের ভার্সনগুলো Rust পোর্ট ব্যবহার করে। Linux-এ স্টার্টআপ ১০% দ্রুত। ইউজার-ভিজিবল বদল নিয়ে Sumner-এর ভের্ডিক্ট: “Boring is good.” (বোরিং ভালো।)
যেখানে পোর্টটা ফসকে গিয়েছিল
৫৩৫K লাইনের একটা বিশ্বস্ত ট্রান্সপাইল ফ্রি নয়। পোস্ট ১৯টা নকন জানা রিগ্রেশন ডকুমেন্ট করে, সবগুলো ফিক্সড। শেখার মতোগুলো হলো ল্যাঙ্গুয়েজগুলোর মাঝখানের ছোট সেমান্টিক ফাঁক:
debug_assert!সাইড ইফেক্ট। Zig-এরassertএকটা ফাংশন, তাই এর আর্গুমেন্ট প্রতিটা বিল্ডে চলে। Rust-এরdebug_assert!একটা ম্যাক্রো যা রিলিজ-এ মুছে যায় — একটাinsert_staleকল যা HMR স্টেট সাইলেন্টলি মিউটেট করছিল, চলা বন্ধ করে দিয়েছিল। (#30678)- অড-লেংথ স্লাইস। Zig-এর হেল্পার একটা ট্রেইলিং অড বাইট ইগনোর করত;
bytemuck::cast_sliceতাতে প্যানিক করে। UTF-16 BOM আর একটা অড বাইট কাউন্টের ওপরBlob.text()ক্র্যাশ শুরু করে দিয়েছিল। (#31188) - বাউন্ডস চেক। Zig-এর
ReleaseFastসেগুলো স্ট্রিপ করে; Rust রাখে। একটা প্লেসহোল্ডার কনস্টান্ট ফাইলনেম-ইন্টারনিং সিলিংটাকে ৮.৪M থেকে ২৭০K-এ নামিয়ে দিয়েছিল, আর আসল প্রজেক্টগুলো সেটায় ধাক্কা খেয়েছিল। (#31503) comptimeফরম্যাট স্ট্রিং। Zig ফরম্যাট স্ট্রিংগুলো কম্পাইল টাইমে এভ্যালুএট করে, তাই কালার মার্কারগুলো আর্গুমেন্ট সাবস্টিটিউট হওয়ার আগেই চলে যায়। Rust-এcomptimeনেই, তাই মার্কার পার্সার OSC 8 হাইপারলিংকে একটা লিটারেল ব্যাকস্ল্যাশ গিলে ফেলেছিল। (#30693)
এগুলোই সেই বাগ যা শুধু এই কারণে বেরোয় যে দুটো ল্যাঙ্গুয়েজ একইরকম দেখায় কিন্তু তা নয়।
এর মানে কী
LLM অ্যাঙ্গেলটা সরিয়ে দাও আর একটা আসল ইঞ্জিনিয়ারিং গল্প আছে: একটা প্রজেক্ট ম্যানুয়াল মেমোরি ম্যানেজমেন্ট যতটা স্কেলে দিতে পারে তার ছাদে ঠোকর খেয়েছিল, আর সে Rust-এর বোরো চেকারকে টুল হিসেবে বেছে নিয়েছিল যাতে বাগের একটা পুরো ক্লাসকে অসম্ভব করা যায়, শুধু ডিসকারেজ করা নয়।
LLM অ্যাঙ্গেলটাই হলো যা নিয়ে লোকে ঝগড়া করবে। Sumner স্পষ্ট বলেছেন যে এতে ফুল কোডবেস কনটেক্সট-ওয়ালা তিনজন ইঞ্জিনিয়ারের প্রায় এক বছর লাগত, আর তাঁরা এটা কখনও করতেনই না — রিয়েলিস্টিক বিকল্প ছিল “কিছু করো না আর বাগ ফিক্স করতে থাকো”। তার বদলে, ৬৪ Claudes-এর তদারকি করা একজন ইঞ্জিনিয়ার এটা ১১ দিনে ~$165K-এ করে ফেলেছে।
Bun-এর Rust কোডের প্রায় ৪% unsafe ব্লকে আছে (~৭৮০,০০০ মোট লাইনের মধ্যে ~২৭,০০০ লাইনে ~১৩,০০০ unsafe কিওয়ার্ড), আর ওই ব্লকগুলোর ৭৮% শুধু এক লাইনের। মার্জের পর থেকে, তারা ১১ রাউন্ড সিকিউরিটি রিভিউ চালিয়েছে আর প্রতিটা পার্সারে ২৪/৭ কভারেজ-গাইডেড ফাজিং যোগ করেছে — এখনও পর্যন্ত ১০০ বিলিয়ন এক্সিকিউশন, ~১৫ PRs।
মেইনটেনেবিলিটি প্রশ্নটাই হলো যেটার দিকে আমি নজর রাখব। Sumner বলেন Rust ঠিক Zig-এর মতোই পড়ে, আর canMergeSymbols-এর একটা সাইড-বাই-সাইড দেখান যাতে পয়েন্টটা প্রমাণ করা যায়। দাওটা হলো যে একটা বিশ্বস্ত পোর্ট পোর্ট-বাই-পোর্ট রিভিউযোগ্য, যেটাই একজন লোককে মিলিয়ন-লাইন ডিফ-এ সাইন অফ করতে দিয়েছিল।
তাঁর ক্লোজিং লাইনটাই হলো যেটা ইন্টারেস্টিং বুড়ো হবে: “One engineer can do a lot more today than a year ago.” (একজন ইঞ্জিনিয়ার আজ এক বছর আগের চেয়ে অনেক বেশি করতে পারে।)