Its way easier than that. As @ceriseraine mentioned you can find a great example in the Tranek’s documentation.
The principle is the following:
-shoot a bullet via a GameplayAbility
-pass on a GameplayEffectSpecHandle to the bullet.
-on bullet overlaps/hits you deliver that GameplayEffectSpec on whatever you’ve hit.
-The rest of the resolution becomes like any GameplayEffect.
No need to track all your bullets, and since you’re adding a simple pointer to your bullet (to a GameplayEffectSpec) the cost is negligible.