He is the first player to beat Federer in 2018.
Del Potro saved three match points before closing out victory in two hours 42 minutes.
The 29-year-old has been hampered by wrist problems in recent years and has had three operations which left him struggling to use his backhand.
But he has made a strong start to 2018, winning his first ATP 500 title for five years at Acapulco earlier in March and returning to the world’s top 10.
Del Potro claimed a stunning four-set win over Federer at the US Open in September last year, but Federer won their last meeting in Basel a month later.
The Argentine forced the only break of the first set and made just three unforced errors to Federer’s 11 as he closed out the first set in 39 minutes.
Federer faced break points in the opening game of the second set but an emphatic forehand forced deuce, before the Swiss served his way out of trouble.
He created two set points on Del Potro’s serve but the Argentine drew the errors out of the Federer forehand to take the set to a tie-break.
Both players complained to the chair umpire during the encounter in California
Cheered on by the crowd, Federer thought he had forced a deciding set with a serve out wide, but a Del Potro challenge showed it to be out and the Swiss then double faulted for 6-6.
Federer had to save a championship point after some superb, quick serves from Del Potro and then finally closed out the set on his fifth attempt.
Del Potro complained to the umpire at the changeover about the noise from a crowd that was largely supporting Federer in an increasingly feisty encounter.
It was Federer who broke first in a tight final set to serve for the match but Del Potro saved two championship points and thrashed a forehand through the Swiss to put the match back on serve at 5-5.
Both players held serve for a decisive tie-break but a combination of loose serving from Federer and some powerful returns from Del Potro saw the Argentine secure victory at the third attempt.
“It’s difficult to describe with words. It’s like a dream,” Del Potro said.
“After all my problems, after all my surgeries, I couldn’t believe I’m here winning a Masters 1000 and beating Roger. It’s amazing.”