First, we need to acknowledge the std
feature flag in Substrate is very imperfect. It represents both a separation of std
from no_std
, but it also USUALLY implies wasm
. It has been noted before that with hindsight, we would have explicitly made a wasm
or runtime
feature flag, rather than jumping on top of no_std
. That being said, wherever no_std
shows up, we must pretty much assume it is Wasm.
Going back to the question, AFAIK it is very much about both the Wasm size, and the fact that serde
itself should never really leak into the runtime.
The runtime should only need to speak in SCALE.
serde
is only used in specific situations on the client side, for example to parse JSON for the genesis_config
/ chain_spec
. This can leak into the runtime, where some runtime struct is getting exposed to the client and through some non-SCALE interface, and therefore a struct would need to implement serde::{Serialize, Deserialize}
, feature gated by std
.
That being said, you could bring in serde
with no_std
into your runtime / pallet if you wanted. For example, if you explicitly wanted to parse a JSON file through an extrinsic, this should all be doable, however this is probably not even the best option. There are libraries like lite-json
written by our community to be extremely lightweight in the runtime, or even better use SCALE in the first place.
So in summary, yes Wasm blob size is one reason, but perhaps even more concretely, there shouldn't be need for serde
in the runtime, as you have SCALE
, therefore, we always feature gate it.