Benchmarking Go's 3D Bin Packing Libraries: Building GoPackX
I benchmarked every Go bin packing library across 7 scenarios. Here's what I found about correctness, performance, and why I built GoPackX.
The Problem
If you ship physical products, you’ve faced this: given a set of items and available box sizes, which boxes should you use and how do you pack them to minimize waste, cost, or total boxes?
This is the Variable-Sized Bin Packing Problem (VSBPP) — it’s NP-hard, meaning no known algorithm guarantees an optimal solution in polynomial time. But good heuristics get close.
I needed a Go library that could handle multiple box types, respect weight constraints, and optionally minimize cost. So I surveyed the ecosystem, benchmarked everything, and built GoPackX to fill the gaps.
The Go Ecosystem for 3D Bin Packing
The Go ecosystem for 3D bin packing is surprisingly small. Here are the libraries with meaningful adoption:
| Library | Stars | Last Updated | Weight Support | Multi-Bin Types | Cost Optimization |
|---|---|---|---|---|---|
| gedex/bp3d | 102 | 2024 | Field exists, not validated | Partial | No |
| bavix/boxpacker3 | 9 | 2025 | Yes | Yes | No |
| stevenferrer/packme | 8 | 2021 | Not supported | Yes | No |
| GoPackX | — | 2026 | Yes | Yes | Yes |
None of the existing libraries offer cost-per-box optimization or cross-bin metaheuristic search. That’s the gap GoPackX fills.
Benchmark Methodology
I tested all four libraries across 7 scenarios with increasing complexity, measuring:
- Bins used — fewer is better
- Unfitted items — items that couldn’t be packed (0 is the goal)
- Fill ratio — volume utilization (higher is better)
- Weight correctness — whether weight constraints are respected
- Execution time
All scenarios use deterministic random seeds for reproducibility. Each library receives identical inputs. The benchmark code is available on GitHub for verification.
Results
Scenario 1: Small Order (5 items, 1 box type)
The baseline — simple enough that every library handles it correctly.
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 1 | 0 | 43.5% | Yes | 19us |
| GoPackX+Optimize | 1 | 0 | 43.5% | Yes | 50us |
| bp3d | 1 | 0 | 43.5% | Yes | 4us |
| boxpacker3 | 1 | 0 | 43.5% | Yes | 9us |
| packme | 1 | 0 | 43.5% | Yes | 4us |
Takeaway: All libraries perform identically. No differentiation on trivial inputs.
Scenario 2: Medium Order (25 random items, 1 box type)
Weight limit: 30kg. Items range 5-25cm per dimension, 1-5kg each.
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 3 | 0 | 26.1% | Yes | 65us |
| GoPackX+Optimize | 3 | 0 | 26.1% | Yes | 28ms |
| bp3d | 2 | 0 | 39.1% | No | 105us |
| boxpacker3 | 1 | 15 | 53.5% | Yes | 20us |
| packme | 2 | 0 | 39.1% | Yes | 96us |
Takeaway: bp3d achieves better fill by ignoring weight constraints — it packs all items into 2 bins but exceeds the 30kg limit. boxpacker3 only fits 10 of 25 items. packme achieves 2 bins legitimately since it has no weight to enforce. GoPackX uses 3 bins but respects all constraints.
Scenario 3: Large Order (80 random items, 1 box type)
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 8 | 0 | 22.8% | Yes | 429us |
| GoPackX+Optimize | 8 | 0 | 22.8% | Yes | 190ms |
| bp3d | 3 | 0 | 60.7% | No | 1.1ms |
| boxpacker3 | 1 | 69 | 62.5% | Yes | 46us |
| packme | 4 | 0 | 45.5% | Yes | 1.6ms |
Takeaway: The pattern is clearer at scale. bp3d consistently ignores weight. boxpacker3 leaves 69 of 80 items unpacked — essentially failing the scenario. packme packs everything into 4 bins. GoPackX uses more bins but guarantees all constraints.
Scenario 4: VSBPP — Multiple Box Types (30 items, 3 box types)
This is where VSBPP matters. Three box sizes: Small ($5), Medium ($12), Large ($25).
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 7 | 0 | 47.5% | Yes | 328us |
| GoPackX+Optimize | 7 | 0 | 47.5% | Yes | 15ms |
| bp3d | 3 | 0 | 27.8% | No | 53us |
| boxpacker3 | 3 | 1 | 27.7% | Yes | 66us |
| packme | 8 | 0 | 41.6% | Yes | 112us |
Takeaway: GoPackX is the only library that can optimize for cost in this scenario. When costs are assigned, it selects bin types to minimize total shipping cost, not just bin count.
Scenario 5: Weight Constrained (10 heavy items, 10kg limit)
This scenario is specifically designed to test weight enforcement. Items weigh 2-8kg, box limit is 10kg — so most bins can only hold 1-2 items.
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 6 | 0 | 1.3% | Yes | 12us |
| GoPackX+Optimize | 5 | 0 | 1.6% | Yes | 1.5ms |
| bp3d | 1 | 0 | 8.0% | No | 8us |
| boxpacker3 | 1 | 8 | 1.6% | Yes | 4us |
| packme | 1 | 0 | 8.0% | Yes | 7us |
This is the most revealing scenario. bp3d shoves all 47kg of items into a single 10kg-limited bin. packme does the same (it has no weight concept). boxpacker3 only packs 2 of 10 items. GoPackX correctly distributes items across 6 bins, and the optimizer reduces that to 5 by finding better weight combinations.
Scenario 6: Real Order #9904 (17 items, 4 box types)
A real e-commerce order with realistic item dimensions and 4 available box sizes.
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 1 | 0 | 52.9% | Yes | 51us |
| GoPackX+Optimize | 1 | 0 | 52.9% | Yes | 102us |
| bp3d | 3 | 0 | 30.2% | Yes | 15us |
| boxpacker3 | 1 | 0 | 52.9% | Yes | 63us |
| packme | 9 | 0 | 39.2% | Yes | 30us |
GoPackX’s trial packing shines here. By simulating actual 3D placement for each candidate box type, it finds that one 50x40x30 box fits all 17 items — something bp3d misses (using 3 bins) and packme completely fails (9 bins). boxpacker3 matches GoPackX on this one.
Scenario 7: Stress Test (200 small items, 2 box types)
200 items (2-10cm per dimension, 1-3kg). Two box types available.
| Library | Bins | Unfitted | Fill % | Weight OK | Time |
|---|---|---|---|---|---|
| GoPackX | 13 | 0 | 8.1% | Yes | 4.6ms |
| GoPackX+Optimize | 13 | 0 | 8.1% | Yes | 222ms |
| bp3d | 2 | 0 | 30.6% | No | 10ms |
| boxpacker3 | 2 | 160 | 12.9% | Yes | 219us |
| packme | 3 | 0 | 40.4% | Yes | 32ms |
Takeaway: At 200 items, packme achieves the best legitimate packing density (3 bins). GoPackX is more conservative, using 13 bins to ensure all physical and weight constraints are satisfied. bp3d again violates weight. boxpacker3 fails catastrophically — 160 items left unpacked.
Key Findings
1. Weight Enforcement is Broken or Missing
bp3d (the most popular Go library) has a MaxWeight field in its Bin struct, but never validates it during packing. Every weight-constrained scenario showed violations. If you’re shipping boxes with carrier weight limits, bp3d will produce invalid packings.
packme has no weight concept at all.
boxpacker3 enforces weight correctly but frequently fails to pack items entirely — leaving up to 80% of items unfitted in some scenarios.
GoPackX is the only library that both enforces weight constraints correctly and packs all items.
2. No Library Offers Cost Optimization
In real logistics, a Small box ($5) and a Large box ($25) are not interchangeable. You need to minimize total shipping cost, not just bin count. GoPackX is the only Go library with a BinCost field and cost-aware solvers.
3. Spatial Efficiency Varies
GoPackX’s trial-based bin selection produces tighter packings when choosing between multiple box types (Scenario 6: 1 bin vs 3-9 bins). However, for single-bin scenarios with many items, simpler heuristics like packme sometimes achieve better density.
4. The Metaheuristic Pays Off
GoPackX’s Optimize() mode uses Variable Neighborhood Search to redistribute items across bins. In the weight-constrained scenario, it reduced 6 bins to 5 — a 17% improvement over the greedy solver.
Architecture of GoPackX
Three layers, each independently useful:
Placement Engines handle the 3D geometry — where exactly does this item go inside this box? Four engines available: Pivot Points, Extreme Points, MaxRects, and LAFF.
Strategies decide item ordering: Best Fit Decreasing (large items first, tightest bin), Minimize Bins, Greedy, and more.
Solvers orchestrate the full packing:
- TrialPacking — simulates real 3D placement for each candidate box type before committing. This is why GoPackX finds 1-bin solutions where others use 3-9.
- Metaheuristic (VNS) — starts from the greedy solution and improves it with four operators: MOVE items between bins, SWAP items, REPACK (eliminate a bin), CHANGE_TYPE (downsize to cheaper box).
Every modification is validated with the actual 3D placement engine — no volume-only shortcuts.
When to Use What
| Need | Recommendation |
|---|---|
| Quick single-bin packing, no weight | packme — simplest API, decent spatial efficiency |
| Multi-bin with weight constraints | GoPackX — only correct option |
| Cost optimization (VSBPP) | GoPackX — only library with this feature |
| Cross-bin optimization | GoPackX + Optimize() — VNS metaheuristic |
| Maximum spatial density, no constraints | packme — best fill ratios in unconstrained cases |
Try It
go get github.com/jcoruiz/gopackx
Three lines to pack an order:
result, _ := gopackx.Pack(ctx, binTypes, items)
fmt.Println("Bins used:", len(result.Bins))
fmt.Println("Fill ratio:", result.Stats.FillRatio)
Add gopackx.Optimize() for cross-bin optimization:
result, _ := gopackx.Pack(ctx, binTypes, items, gopackx.Optimize())
Zero dependencies. Go 1.22+. Full documentation on pkg.go.dev. Source on GitHub.