Pachuca Herrera began playing football for
C.F. Pachuca's
youth sides. As a youth, he was nicknamed
Zorrillo (skunk), as well as
Zorro (fox). Herrera made his
league debut for Pachuca in a 1–4 home defeat to
Santos Laguna on 23 July 2011. Appearing 14 times for Pachuca in the
2011 Apertura, he was a shortlist candidate for best rookie of the tournament.
Porto On 28 June 2013, it was announced that Herrera was transferred to Portuguese club
Porto for €8 million. Herrera was an unused substitute in
his first season's opening
Super Cup match against
Vitória de Guimarães on 10 August, ultimately winning 3–0. Eight days later, Herrera made his
Primeira Liga debut, coming on as a substitute for
Lucho González in the 82nd minute in Porto's 3–1 victory over
Vitória de Setúbal. On 6 October, Herrera played his first 90 minutes in Porto's 3–1 away win over
Arouca. On 18 September, Herrera made his
UEFA Champions League debut against
Austria Wien in a 1–0
group stage victory. On 22 October, Herrera set a new UEFA Champions League record for the fastest dismissal for two yellow cards when he was sent off in the sixth minute of the group stage match against
Zenit Saint Petersburg. Herrera scored his first league goal with Porto on 20 December in a 4–0 win against
Olhanense, scoring on a
volley just eight minutes after coming on as a substitute. In his
first season with Porto, Herrera played in 17 league matches, and in 33 across all competitions, scoring three goals in total, all of which were scored in the league. On 20 August 2014, Herrera scored his first goal in
Champions League play in Porto's 1–0 win over
Lille. On 25 November, he played an important role in Porto's 3–0 Champions League
away win over Belarusian club
BATE Borisov, scoring the first goal of the game and providing two assists, all in the second-half. Herrera was included in
The Guardians year end list of "
The 100 Best Footballers in the World". On 22 August 2015, Herrera scored his first goal of the
season in Porto's 1–1 draw against
Marítimo at the
Estádio dos Barreiros. In December, Herrera was given the
Dragão de Ouro Award as the team's best player of the
previous season, the first Mexican to win the honour. On 12 February 2016, Herrera, wearing the
captain's arm-band, scored the equalizer in Porto's 2–1 win over
archrivals Benfica. Herrera was called up for the
final of the
Taça de Portugal against
Braga on 22 May 2016, playing in the 120 minutes of the match and failing to convert his penalty shot in the subsequent 3–2 shoot-out defeat. On 15 April 2018, Porto defeated Benfica 1–0 at the
Estádio da Luz, with Herrera scoring in the 90th minute from a shot outside the box. The win took Porto to the top of the table with 76 points, two ahead of Benfica with four matches remaining in the
season. His goal was ultimately voted as the season's best. On 5 May, after a 0–0 draw between Benfica and
Sporting CP, Porto won the league title with two games left to play. Herrera featured in the season's Team of the Year, one of five Porto players included. in 2018. On 4 August 2018, Herrera began the
2018–19 season captaining Porto in their
3–1 win over
Aves to clinch the
Supertaça Cândido de Oliveira. On 22 September, Herrera made his 200th appearance for Porto in all competitions following a 2–0 victory over
Vitória Setúbal. In March 2019, he captained Porto in their 4–3 aggregate victory over
Roma in the
Champions League round of 16, with Porto reaching the quarter-finals for the first time since the 2014–15 competition. On 30 March, Herrera, in captaining Porto to a 3–2 victory against Braga, made his 237th appearance in all competitions for the
Dragões, placing him fifth in the club's all-time list of appearances by a foreign player, four games behind Lucho González. Amid reports linking him to
Atlético Madrid, Porto president
Pinto da Costa confirmed Herrera would leave the club on the expiration of his contract. On 18 May, Herrera scored in his final Primeira Liga game with Porto in the team's 2–1 victory over
Sporting CP, scoring a
scissor kick from a corner kick. He was again included in the season's Team of the Year.
Atlético Madrid On 3 July 2019, Atlético Madrid announced via their website that they had reached an agreement with Herrera. He signed a three-year contract, and was officially presented at the
Wanda Metropolitano with the number 16 shirt. After failing to appear for
Los Rojiblancos in the first month of the season, he made his competitive debut on 18 September, coming on as a late substitute for
Thomas Partey and scoring the equalizer in the 90th minute to salvage a 2–2 draw against
Juventus in the opening group game of the
UEFA Champions League. Three days later, Herrera made his debut in
La Liga as a starter against
Celta de Vigo, playing 60 minutes in a scoreless draw. He was a starter in both
Supercopa de España matches against
Barcelona and
Real Madrid, finishing runner-up against the latter in the
final. He made 30 appearances across all competitions in his debut season with Atlético, though his playing time was mostly hampered due to injuries. At the start of the
2020–21 season Herrera was on a positive run of form, featuring eight times in all competitions and starting in the team's last four games prior to the international break, before being ruled out of action in November. It was reported that he had suffered a grade two injury to his left thigh while on international duty with Mexico, and would be out of action for a month. On his return on 1 December, Herrera, with 47, surpassed
Javier Hernández as the Mexican with most UEFA Champions League appearances, coming on as a substitute in a 1–1
group stage draw against
Bayern Munich. He again faced a spell on the sidelines, both due to injury and testing positive for
COVID-19 in February. In December 2021, Herrera tested positive for COVID-19 a second time.
Houston Dynamo On 2 March 2022, Major League Soccer club
Houston Dynamo announced that it had signed Herrera on a pre-contract agreement through the 2024 season with an option for 2025. He committed to the club as a
Designated Player. On 3 November 2024, during a MLS Cup match, Herrera was sent off in the 65th minute for spitting towards a referee following a disagreement on a foul. He was handed a three-game suspension and was fined an undisclosed amount. On 6 November, Houston Dynamo opted not to pick up Herrera's contract option and released him.
Toluca On 2 January 2025, Herrera returned to Liga MX, joining
Toluca. During his time with the club, he helped the team win two league championships. He departed on 7 January 2026.
Return to Houston Dynamo On 14 January 2026, Herrera signed with Houston Dynamo, starting his second spell with the club. ==International career==