Hamilton led away from pole, as a slow start for teammate Bottas allowed a lunge by Lance Stroll into turn one. Bottas dropped down to fourth as Verstappen and Stroll got through.
Charles Leclerc looked to challenge Pierre Gasly for eighth coming through turn eight but was unable to make the move. Regaining third off Stroll on lap five, Bottas set after the second-place of Verstappen.
Verstappen was able to hang onto the rear of Hamilton in the opening laps, leading Verstappen to suspect the Mercedes was driving slower than normal.
Further down, Sebastian Vettel battled with the AlphaTauri of Daniil Kvyat, with the Russian driver looking to take tenth of the Ferrari at turn one. He could not make the move stick and stayed behind the German.
By lap thirteen, Verstappen was starting to feel uneasy on the tyres, as Hamilton then started to extend the gap from the Red Bull with a series of fastest laps.
Red Bull teammate Alexander Albon was the first to pit, coming in on lap eighteen for a set of hard tyres. He rejoined behind Esteban Ocon and Kimi Raikkonen, getting past the Finn after Ocon overtook the Alfa Romeo at turn one, leaving the Finn vulnerable to the Red Bull on fresh tyres.
Verstappen then pitted on lap 22, after repeatedly reporting to the team that he could no longer go on the worn soft tyres. A stellar 1.9 second stop saw him rejoin in fourth.
Hamilton came in from the lead on the following lap, suffering a slightly slower stop as the team struggled with the rear tyre. The team double-stacked the two drivers, Verstappen coming out ahead of Bottas.
Albon moved up to the points with a quick move around the outside of Kevin Magnussen at turn three on lap twenty-nine, with Carlos Sainz also moving past the Haas, which had yet to pit.
Sainz then passed the Red Bull for tenth on the faster soft tyre, while further back, Sergio Perez's pitstop dropped him right into the traffic, coming out of the pits in seventh ahead of former teammate Ocon.
Stroll and Perez took the chequered flag in fourth and fifth, while sixth and seventh went to Sainz and Vettel
As the race reached halfway, the two Racing Points went head-to-head for fifth place, as Leclerc looked for a way around Norris for eleventh.
Verstappen reported dark clouds at turn four, increasing the worry for teams that rain may be on its way. Ocon looked to struggle ahead of Lando Norris as Leclerc tried everything to pass the McLaren ahead of him.
Ferrari told Vettel that the rain was expected after lap 50, as Ricciardo rejoined in thirteenth on the soft tyre.
Leclerc brought out the yellow flags at turn fifteen on lap 38, after his engine stopped, spinning the Ferrari. He was able to restart the power unit and get going again but pitted to retire as he felt a major problem with his power unit.
Albon pitted on lap 41 for mediums, coming back out onto the track in eleventh, as Ferrari pushed Leclerc back into the garage to confirm him as the first retirement of the race.
Verstappen then pitted on the following lap from his teammate, also rejoining the race on medium tyres. Sainz and Albon went wheel-to-wheel for the first sector for tenth after Sainz's second stop, but the Red Bull could not find a way around the Spaniard.
Bottas stopped a second time on lap 49, handing second back to Verstappen, Mercedes wanted to pit Hamilton on the following lap, but Hamilton felt comfortable enough to stay on the medium tyre
Hamilton then pitted on lap 51, taking back the lead with ease, Perez was put under investigation for ignoring blue flags. An impatient Vettel harshly responded to his team when asked if he could go to the end on the soft tyre, having already asked the team before about doing so.
With nothing to lose, Vettel opted to attempt to finish the race on the tyre, currently running in fifth position, as Kvyat was also put under investigation for ignoring yellow flags. After his investigation, Perez was handed a five-second penalty for the incident, Kvyat also handed the same penalty.
Stroll passed Vettel for fifth with ten laps to go, as Raikkonen narrowly avoided an incident with Romain Grosjean on the main straight, the Haas moving while Raikkonen tried to overtake.
In the closing laps, Sainz dropped Vettel down to seventh as he made a late charge up the grid, chasing after Sainz and Vettel. A late stop for Bottas on the penultimate lap gave the Finn the chance to go for the fastest lap.
Grosjean half spun at turn seven but continued in the race, being put under investigation for an earlier collision with Antonio Giovinazzi.
Hamilton crossed the line to take his fourth Spanish Grand Prix win in a row, with Verstappen over twenty seconds behind in second.
Albon and Gasly crossed the line in eighth and ninth, as Norris took the final point in tenth.
Circuit de Catalunya - Winter testing
Circuit de Catalunya - Winter testing