Dart on the Server: Why It Crumbled Under Production Load
A SaaS developer swapped Node.js for Dart to slash memory usage. Expectations: 10 MB startup vs. 80 MB, AOT compilation, and static typing. Reality: two weeks of dev time, a custom framework, and benchmarks showing worse performance. Lesson learned: always run raw benchmarks on production workloads before migrating.
The auth service (OAuth2, Redis ORM) was the test bed. Node.js peaked at 500 MB but released memory. Hundreds of instances at 80 MB startup was the core issue.
Ecosystem: No Backend Tools in Sight
Dart is built for Flutter. No NestJS equivalents, few Redis clients match ioredis quality. Shelf is a basic router, Serverpod targets full-stack Flutter apps.
Had to build a framework from scratch:
- Tree-based DI like Angular.
- Request scoping via Zone.
- CLI with codegen for AOT.
Ported ts-oauth2-server and ioredis (4,500 lines Dart vs. 23,500 TS). AI handled it, but at a cost: experimental --enable-experiment=enhanced-parts flag, part 'file.g.dart' everywhere, commit sheets or CI generation.
Reflection is gone for AOT. Type is a stub, no static method calls. DI without mirrors needs CLI in JIT → mirrors → codegen. In TS/Java/C#, it's three lines of reflection.
Language: Nice Syntax, Terrible for Metaprogramming
Logical syntax, compile-time errors. But no for...in on objects, no reflection. Codegen is a nightmare: .g.dart references clutter source files.
AI ported ioredis mechanically. Result: +5% RPS over the best pub.dev client. RIP backend ecosystem—nobody writes server code in Dart.
Benchmarks: Latency and Memory Kill It
Scenario: 3 endpoints, Postgres, Redis. Raw HTTP, no frameworks. 100m CPU, 500 VUS.
| Metric | Dart AOT | Node.js | Go |
|---------|----------|---------|----|
| RSS startup | 3 MB | 18 MB | - |
| p95 latency | 9.5 s | 5 s | 2.9 s |
| RPS | 2x worse than Node | - | Best overall |
| Peak RSS | 39-47 MB | 37 MB | - |
Dart:
- Doesn't return memory to OS (>5% after peak).
- GC under pressure: pauses tuned for 60fps (Flutter), not RSS for K8s.
- Under throttling, balloons to 47 MB; Node shrinks.
GC flags (--dontneed_on_sweep, --use_compactor) didn't help. By design: VM for mobile. K8s sees 40 MB/pod constantly, HPA can't pack nodes tightly. Startup savings eaten by overprovisioning.
On Cloud Run: Dart costs more than Node—slower + holds memory.
Key Takeaways:
- p95 latency 9.5 s vs. 5 s Node = production failures.
- Memory not released: scaling overcharges.
- Ecosystem dead outside Flutter.
- Benchmarks in repo: K8s manifests, CPU profiles, Dockerfiles.
Verdict: Dart's Niche Is Flutter Only
Two weeks lost to framework, ports, tests. Dart shines for simple code, but server-side is a bust. No reflection, VM not cloud-ready, codegen hell. Official "scalable APIs for Cloud Run" promises fell flat.
Rejected Go over err != nil and context.Context. Node.js wins: releases memory, better latency.
— Editorial Team
No comments yet.