there is a difference,
Ipairs is currently the fastest generator and can iterate through index-value pairs which is faster than iteration in key-value pairs.
pairs uses the next iterator function so returns nil being nil encountered in a contiguous array, ipairs however is different as it will stop the iteration rather than returning nil. Pairs has also has no specific order for non-numerical indices, it iterates over all indices , while ipairs doesn’t index non-numerical indexes in the first place.
If it is just a matter of iterating through a simple array, there will be no difference in the output of ipairs and pairs though there will be a difference in speeds.
It is recommended that you use pairs when you want to index all elements.
Example :
dictionary = {
["things"] = 1;
["xyz"] = "a";
["name"] = "k"
}
for k, v in pairs (dictionary) do
print(k..v)
end
Output :

however you cannot index non-list items with ipairs, so doing the same with ipairs instead will give this output :

Nothing.
Note that ipairs is built to work with arrays with numerical indices, pairs is designed to work with dictionaries.
Here is a small experiment I did to find the average time taken by different means of iteration to execute code:
DO NOT use pairs incorrectly, please