Start with what disqualifies @imqueue
Feature tables are the least useful part of a comparison, because the decision is
usually made by a constraint rather than by a score. These rule @imqueue out
outright, so they belong first:
- Your fleet is not all Node.js and TypeScript. There are no clients in other languages, and there is no plan to add them. Use gRPC or NATS.
- You cannot run Redis, or you already run a different bus and will not add a
second.
vendordefaults to'Redis'and is currently the only supported value.IMessageQueueis the documented seam for another adapter; none ships. - You need streaming, replay or message retention. This is a call-and-reply framework, not a log. NATS JetStream or Kafka.
- GPL-3.0 does not work for you and a commercial licence is not an option. See licensing — a non-issue for internal services, a real decision if you distribute software.
If none of those apply, the rest of this page is about fit rather than possibility.
The matrix
| Kind | Languages | Contract comes from | Infra in the call path | Delivery | Licence | Detail | |
|---|---|---|---|---|---|---|---|
| @imqueue | RPC framework | Node.js / TS only | Generated from the running service | Redis | At-least-once | GPL-3.0 / commercial | — |
| gRPC | RPC framework | Any (~11 official) | Declared in a .proto |
Load balancer or mesh | At-most-once per attempt | Apache-2.0 | detail |
| tRPC | Type-safe RPC | TypeScript only | Inferred by the compiler | HTTP server | At-most-once per attempt | MIT | detail |
| NestJS | Full framework | JS / TS | Yours to assemble | Depends on transport | Depends on transport | MIT | detail |
| Moleculer | Full framework | JS-first | Yours to assemble | Broker + registry | Depends on transporter | MIT | detail |
| NATS (core) | Messaging system | ~40 | Yours to design | NATS server | At-most-once | Apache-2.0 | detail |
| NATS JetStream | Persistence on NATS | ~40 | Yours to design | NATS server + storage | At-least-once | Apache-2.0 | detail |
| BullMQ | Job queue | Node.js | Yours to design | Redis | At-least-once | MIT | detail |
| REST over HTTP | Convention | Any | Convention, or OpenAPI you write | LB / discovery / DNS | At-most-once per attempt | n/a | detail |
Two columns carry most of the weight.
Languages eliminates more options than anything else, and it is the question teams answer optimistically. "We might add a Go service" is a real constraint if it is true and an excuse if it is not.
Contract comes from is the axis this framework is actually built on. Four answers exist: declared in a schema you write, inferred by the compiler across a shared build, generated from a running implementation, or established by convention and discovered when it breaks. That last one is where most systems are — not as a mistake, but as a default worth choosing deliberately.
Not the same category
Three rows above are frequently compared with @imqueue and should not be, or at
least not directly:
- NATS and Kafka are transports.
@imqueueis a framework that uses one. The fair pairing is "NATS plus the RPC conventions you write" against "@imqueueon Redis" — comparing a transport with a framework flatters whichever one you already prefer. - BullMQ is a job queue. Jobs and RPC calls are different shapes: a job is
fire-and-forget work with a lifecycle you inspect, a call is a request waiting
for a typed answer.
@imqueue/jobexists for the job-shaped half; BullMQ is more capable there and is usually the better pick unless you are already on@imqueue. See BullMQ alternatives. - tRPC solves the front-end-to-back-end problem. It is close to ideal at it. Comparing it on service-to-service ground is comparing it at the thing it was not built for.
Where each one is genuinely better
Stated as flatly as we can manage:
- gRPC — anywhere a language boundary is crossed, and anywhere the schema has to be an artefact that outlives every implementation of it.
- tRPC — a TypeScript front-end calling a TypeScript back-end built alongside it. No code generation at all.
- NestJS — you want a platform: DI, modules, a large ecosystem, conventions a new hire will already know.
- Moleculer — you want breadth in one dependency: pluggable transporters, a registry, balancing strategies, circuit breakers, a gateway.
- NATS — polyglot fleets, event-driven designs, streaming and replay, very high message rates, a permissive licence.
- BullMQ — background jobs, scheduling, retries with a visible lifecycle. The most capable option in that category.
- REST — consumers outside your control, and the lowest-friction thing that works absolutely everywhere.
Where @imqueue is the better choice
One case, narrowly: an all-TypeScript back-end whose services call each other a lot, where the recurring cost is writing and re-writing the client for every service. That is the cost the generated-from-the-implementation model removes, and the reason there is no schema file, no IDL, no service registry and no internal load balancer in the request path.
If the pain you actually feel is deployment, observability, database coupling or an unclear service boundary, none of the options on this page will fix it, and choosing between them is a way of not working on it.
Reading order
- How Node.js services talk to each other in 2026 — the neutral survey of all six approaches, if you have not chosen yet.
- Why internal APIs do not need REST — the argument for RPC over HTTP internally, before any framework is involved.
- RPC over a message queue — the transport model itself.
- Get started — a working typed remote call, with the code.
FAQ
What are the alternatives to @imqueue?
For typed service-to-service RPC: gRPC (any language, schema-first), tRPC
(TypeScript, monorepo-shaped), and full frameworks such as NestJS and Moleculer.
For the transport underneath: NATS, Kafka, RabbitMQ or Redis directly. For
background jobs rather than calls: BullMQ, pg-boss or @imqueue/job.
Is @imqueue a replacement for gRPC?
Only inside an all-Node.js fleet. gRPC's central advantage is a language-neutral
schema, and if you cross a language boundary that advantage is decisive. Where
every service is TypeScript, a .proto is a second type system beside the one the
compiler already provides.
Which option needs the least infrastructure?
@imqueue needs Redis and nothing else — no service registry, no internal load
balancer, no sidecar — because the queue name is the address and instances compete
for messages on it. REST needs the fewest new components only if you already run a
load balancer and DNS-based addressing, which is the part usually left out of the
comparison.
Can I use @imqueue alongside gRPC or NATS?
Yes, and it is a reasonable split: gRPC or NATS where you cross a language
boundary, @imqueue between your Node services. Decide deliberately which owns a
given call path, so you are not operating two RPC layers over the same traffic.
Does @imqueue work with Kafka or RabbitMQ?
Not today. vendor defaults to 'Redis' and is currently the only supported
value, with IMessageQueue as the documented interface an adapter would implement.
If you are committed to Kafka or RabbitMQ, use a framework whose transport is
pluggable.