How many is a ton, can you give us an order of magnitude? I can’t imagine a game having a number of named abilities that is anything close to large by computer memory standards.
About the smallest you can get it in a DataStore with simple encoding would be to bit-pack groups of booleans into single-byte characters. While JSON technically has 94 such characters available, using base64 would be a good compromise, because it’s standardized and you can easily get copy-paste code to encode and decode it.
If you need the data even smaller, you have to consider compressing the binary data before you even store it, using standard techniques like run-length encoding, or Huffman coding (or some other entropy coding), to get the data smaller before the binary-to-text encoding.
That said, I was answering your question from a purely academic point of view. I wouldn’t recommend you actually try to achieve the smallest JSON string possible for an array of booleans, your time is better spent.
You can assign integer IDs to all your skills and just store them in a Lua array, which you can write it to a Datastore. It’s going to be bigger than a base64 string, but do you actually care? I’m guessing we’re not talking about 100k unlockable skills here.
Keep in mind that you only really have to store the IDs of either the unlocked skills, or the locked skills, so you only ever need to have up to 1/2 the IDs in your save data. If a player has unlocked more than half the skills, you save the list of ones that are still locked, otherwise you save the list of unlocked skill IDs. Then, you just need one more boolean to store whether the saved IDs are the locked or unlocked skills.
But you might not even need to do that, again, depends on how many skills there are and what your real concern is. Just an array that maps integer skill ID to a 1 or 0 for every skill is probably fine.