Zulip has a far more advanced threading model than Matrix. Currently, Matrix only has basic replies in the spec. In practice, everything in a Matrix room is in a single thread. It definitely makes it hard to follow conversations that are long-lived or in busy rooms or both.
Matrix is federated and Zulip isn't. You can run your own Matrix server and communicate with all the other Matrix servers that already exist. Rooms live on multiple servers and are resilient to the failure of any participating servers as long as one remains.
Matrix is far more general than Zulip. It acts as a store for arbitrary, eventually-consistent, ordered JSON data. Most of the time this is used to create an instant messaging service, but it can be used for much more.
Zulip subjectively has a nicer default client than Matrix (Element). Zulip's is special-built to handle its unique threading model.
It's also worth noting that Matrix is adding support for arbitrary threading [0]. I'm really looking forward to this. It should allow us to build a Zulip clone fully in Matrix with all of the benefits that come with the Matrix ecosystem.
[0]: https://github.com/matrix-org/matrix-doc/blob/kegan/msc/thre...