This is rooted in C’s printf, and I only did a cursory reading and am uncertain whether the apostrophe flag for a thousands separator is standard or an extension.

If going in the direction of reimplementing the string formatting instead of installing a package (yet I would think any good implementation is worth sharing as a package), I think changing the number of digits per delimiter, the delimiter character, and the decimal delimiter character can be low-hanging fruit. On the other hand, formats that vary number of digits per delimiter and the delimiter characters by magnitude could be more simply specified by label if finer control would be too complicated.

isn’t the solution to check if the number is negative, if so mark a flag then turn the number positive and perform the function then after the function is done add a negative sign to the front of the string if the number is negative?

function with_commas(num::AbstractFloat, trunc::Integer=3)
negflag = false
if num < 0
negflag = true
num = -1 * num
end
sig = Int(floor(num))
frac = (num - sig)
sig_str = string(sig)
frac_str = string(round(frac, digits=trunc))[2:end]
newstring = replace(sig_str, r"(?<=[0-9])(?=(?:[0-9]{3})+(?![0-9]))" => ",") * frac_str
if negflag == true
newstring = "-" * newstring
end
return newstring
end

This isn’t optimized for speed (too many allocations…) but it may serve as another base for further optimization and parameters such as different bases, and different separators etc:

function with_commas2(num::AbstractFloat, trunc::Integer=3)
d,r = divrem(num, 1000)
s = string(round(r; digits=trunc))
while d > 0
d,r = divrem(d, 1000)
s = string(floor(Int, r))*','*s
end
s
end

Also, perhaps trunc → digits to match round would be nicer.
On x in the post it is 2x faster.