What is the recommended way to do sprite or mesh batching?

Correct, because all instances share the same material. When using InstancedMesh (or instanced rendering in general), there is no way around this.

First of all, three.js does not support auto-batching so applications have to do this task. You can try to start with BufferGeometryUtils.mergeBufferGeometries() by merging all geometries which share a common material. In this way, you can render the merged geometry with a single draw call which can noticeably improve performance.