Resend says its email API now runs entirely on Go, after a seven-week rewrite of the Node.js service that took roughly 140 pull requests, according to the company’s engineering post. With traffic split evenly between the two services, Resend reports that Go showed roughly half the median latency and about one-seventh the memory per task.
Zeno Rocha, Resend’s CEO, shared the post on X on 13 November. He wrote that as a Node.js developer he wasn’t on board at first, “then I saw the numbers.” Resend’s own account described the project as moving “our most critical API to Go.”
Why Resend moved off Node
Resend says the Node service had two failure modes. During bursts of large requests, a whole task could become unresponsive. One investigation traced that to parsing and serialising large request bodies, including requests the rate limiter was already rejecting. Both are CPU-heavy operations that run synchronously in Node, so they block the event loop, the single thread that runs Node’s code, until they finish.

The second problem was storage. Resend says S3 timeouts surfaced as customer-facing 408 and 524 errors. Those two problems set the requirements for the replacement: predictable behaviour under load, lower resource use, and control over how long each operation can take.
How Resend checked the two services agree
Resend built a harness that sends the same requests to Node and Go and compares what each does. It covers responses and errors, database rows, S3 objects, idempotency (the guarantee that repeating a request doesn’t send a second email) and rate limits. The company says checking the HTTP response alone would leave too much untested, because both services could return a success while saving different metadata or producing different email content.

The old service became the reference, and Resend kept some Node quirks on purpose, since changing unexpected behaviour can break an integration that depends on it. Its example is the conversion of HTML-only emails to plain text. The Go library Resend first picked produced reasonable text but differed from the Node library: elements marked data-skip-in-text="true" appeared in the output, and links could gain URL text. Resend wrote a Go port of the specific behaviour its API uses, and says the first version matched all 60 fixtures generated from the Node implementation.
Derich Pacheco, one of the two engineers interviewed in the post, says much of the API’s behaviour lived in Node and its npm packages rather than in Resend’s own code. His example is attachments: the Node SDK accepts a Buffer, which JSON.stringify turns into a JSON object, and Node turned it back into bytes with one call. Go has no Buffer, so the team rebuilt that conversion by hand, JavaScript’s coercion rules included.
What the rollout needed
The new service used fewer resources per request, but Resend says it still had to double task sizes twice during the rollout. It also added capacity ahead of a recurring top-of-hour traffic spike, introduced per-request timeouts for S3 uploads and tuned Redis connection pools as traffic grew. Fabio Kubo, the other engineer interviewed, says a widget showing the split of HTTP status codes gave the team a quick check that the new service behaved like the old one, because a random share of requests went to each.
Pacheco says the team deleted some of the Node code once the port was stable. Parts of the old service existed only to protect the event loop, and he describes the email-size check as having had an elaborate trick to avoid scanning large bodies byte by byte, which the team cut down to the one part that still saves CPU. He also says the batch endpoint went from the decision to move it to production traffic in about a week.
The numbers
Resend’s figures come from the 50% rollout, with half of requests on Node and half on Go, both on the same task size. It says Go used about 62% less CPU per request. Median latency for POST requests to /emails fell by roughly 50%, and p99, the latency 99% of requests come in under, fell by about 16%. Resend says much of the slow tail is time spent waiting on S3 and the database, so cutting it further means work on those dependencies.

| Metric | Node | Go |
|---|---|---|
| POST /emails median latency | 58 ms | 31 ms |
| POST /emails p95 latency | 149 ms | 107 ms |
| POST /emails p99 latency | 498 ms | 420 ms |
| Batch median latency | 149 ms | 74 ms |
| Batch p99 latency | 1,721 ms | 1,363 ms |
| Tasks at peak | 34 | 10 |
| Memory per task | ~1.3 GB | ~180 MB |
| CPU per request (normalised) | 1.00x | ~0.38x |
Resend titles that section “The preliminary results” and gives no figures for all-Go traffic. On 10 November the company also made its own sending infrastructure, Forge, available to every customer.
Discover more from Sulat AI & Tech News
Subscribe to get the latest posts sent to your email.




