When creating a ERC721 contract that manages thousands of image NFTs, saving these image byte pixels in arrays on the contract doesn't seem very scalable.

What is the standard way of doing this?

For eg. CryptoKitties, are they storing each image bytes on the contract itself, or they are a URI pointing to an external resource?

On the other hand, having an URI seems to beat the point of NFTs, because if the URI gets broken (eg. the server with the image goes offline), then as a owner of that NFT, you now only own a URI reference to what would be an image, and not the image itself.