Sometimes you need to attach data to an ItemStack, in order to keep track of something. A project I'm working on is for an RPG themed server where they want items that act as teleportation scrolls. When interacted with, they open a GUI where players can teleport to pre-defined areas. Each individual item had a limited amount of uses, as well as a cooldown.
Using NBT data, you can attach whatever kind of data you want to items. NBT acts very similar to JSON (in fact, the string representation could almost be parsed that way), so you could add strings, integers, lists, whatever. In this case, I had an object called ScrollData with three fields - the Scroll it belonged to (the Scroll object kept track of things like how many uses a scroll starts with and where it can teleport to), the remaining uses, and the next time the scroll can be used as a millisecond timestamp (cooldown).
One way to store data would be to create NBT tags for all three fields. Instead, though, I generated a random ID for the item and tied an object to it. Then I stored the item in a YAML data file. On startup, I load all of the data up. The only NBT data that needs to be stored is the ScrollData UUID I generated for the item.