To elaborate more on your point, CRDTs are super helpful while trying to distribute a lot of devices, but they only get you so far. While building Lasp[0][1], a distributed data-flow language using CRDTs, we found out a lot of scalability problems with naive usage of CRDTs. We are aiming to reach 10k-20k nodes in the near future, so we are focusing a lot on reducing network usage.
State-based CRDTs send their full state to all their peers, which works ok when your states are small, but they introduce lots of overhead in any other case. Operation-based CRDTs only send the actions performed on it (add 1, or rmv 2, for example), but these are not idempotent and require a lot of guarantees from the underlying distribution backend.
We are focusing on using Delta CRDTs, that combine the low network usage of operation-based structures, with the idempotence of state-based approaches.
Using plumtree for your backend makes it resilient to network failures, but using the default full membership protocol makes it almost unusable when you're dealing with a big number of nodes. Using alternative protocols like Hyparview greatly reduces the number of protocol messages in your network.
Finally, since Lasp is a data-flow language, we are applying control-flow analysis to select and remove unused or intermediate values in the program, thus also reducing network usage.
[0]: http://lasp-lang.org/ [1]: https://github.com/lasp-lang/lasp