It depends. If you can, keep things simple. But if you have a more complicated scenario (hundreds of microservices, lots of different teams, etc), you probably should consider a couple of things when gluing your services together: How will the messages evolve over time? Are your microservices written in different languages? Is there good library support for all of them? How will you handle the messages flow? Retry on errors? Circuit-break? Tracing for debug purposes? What guarantees does your transport offer? Do you need to be concerned with duplicated messages? It's hard to isolate communication (transport channel and message format) from other challenges inerent to microservice architectures such as: Traceability, monitoring, circuit-break, load-balancing, etc. It's desirable that your tools play well together to solve these problems. Details: (1) Your services will change with time and when it happens how the services will handle it? The changes are backwards compatible, do you need to orchestrate the deployment? (i.e redeploy both services with the new message format?) Is there a possibility that your service will receive messages in the old format, if yes what happens? (is your service backwards-compatible?) Some communication schemes may help you with the questions, above: Avro, gRPC (protobuf), Thrift have their our evolution scheme. Here's a good article about the topic: Schema evolution in Avro, Protocol Buffers and Thrift (2) Why does it matter if your services are written in different languages? Well, if you need to write a library for each language to standardize the communication, that's a lot of effort. If everything is in the same language, you can share your communication library. For example: If you are in the JVM, you can use something like Finagle , if you have lots of teams writting stuff in different languages you could use something like Istio (3) If you have 200 microservices talking with each other in production, you need standards and order. For example: How do you handle errors? Is there a common error format? Retrying/resending messages is supported in the transport layer or you have to do that on the application side? Does it make sense to separate transport errors from application errors? (4) If you are using some sort of message broker or queue, how are the messages routed? Is there any need to add an deadletter queue? If the messages may be delivered more than once you need some sort of idempotency mechanism.