Having used both (from Python) I found NATS much better. ZeroMQ in particular caused a lot of problems around the HWM (High Water Mark) limit for me or around process starting order (who creates what channel). Having a separate server helps with the last problem.
ZMQ for me fills a very specific use case of needing high-throughput, _in-process_ distributed messaging.
I think once the _in-process_ constraint is lifted -- you can install or rely on an external messaging server -- then the field becomes much wider in terms of solutions to pick from.
BTW, the way we solved for a similar HWM issue is that we decoupled the ingestion of events from the distribution of said events (with ZMQ). So one process was ingesting events and would send it to a coordinator process that would then send events to processing nodes. The coordinator would reply with it's current queue size and the ingest process would do a back-off once it reached a threshold. This allowed us to stop/start any node in the cluster in any order.
Sure, to get the most out of NATS you should run it as a server (which frankly isn't difficult as its a single Go binary).
But you can embed it if you so wish. Indeed if you look at the NATS source code[1], that is exactly how NATS do their testing. They use an embedded NATS server in their test routines.
Exactly, zmq is far more flexible in deployment options because of this.
We (at work) use ZMQ + our own special sauces to run vehicle automation messaging stuff. Running some enterprise-ish broker in that environment just isn't on the menu.