Year in Review: The 2025-26 NHL Season

Hockey
Featured
Season Recap
A full season of NHL boxscore data, pulled through the hockey pipeline into BigQuery: the scoring race, the goaltending duels, and how the league’s best regular-season team still didn’t win it all.
Published

July 8, 2026

The hockey pipeline has now pulled a complete season: every regular-season and playoff game from the 2025-26 NHL season, backfilled game by game into BigQuery. This post is the first real analysis built on top of it, a look back at the season through the same data the daily pipeline keeps adding to.

One wrinkle worth flagging up front: the NHL’s schedule API also listed games from the Milano Cortina Winter Olympics during the league’s February break, tagged with a different game type than regular-season or playoff games. Those are country-vs-country games, not NHL team games, so they’re filtered out of everything below.

Querying the season

from google.cloud import bigquery

client = bigquery.Client()

query = """
SELECT
  player_name,
  team,
  SUM(goals) AS goals,
  SUM(assists) AS assists,
  SUM(points) AS points,
  COUNT(DISTINCT game_id) AS games_played
FROM `maydaystats.nhl_stats.boxscores`
WHERE CAST(SUBSTR(CAST(game_id AS STRING), 5, 2) AS INT64) IN (2, 3)
  AND position_group != 'goalie'
GROUP BY player_name, team
ORDER BY points DESC
LIMIT 10
"""

scorers = client.query(query).to_dataframe()
scorers
player_name team goals assists points games_played
0 N. MacKinnon COL 64.0 86.0 150.0 93
1 C. McDavid EDM 49.0 98.0 147.0 88
2 N. Kucherov TBL 47.0 91.0 138.0 84
3 N. Suzuki MTL 33.0 89.0 122.0 101
4 M. Necas COL 42.0 79.0 121.0 91
5 J. Eichel VGK 31.0 88.0 119.0 96
6 M. Celebrini SJS 45.0 73.0 118.0 82
7 D. Pastrnak BOS 33.0 79.0 112.0 83
8 K. Kaprizov MIN 52.0 59.0 111.0 89
9 M. Marner VGK 34.0 77.0 111.0 103

N. MacKinnon led the league with 150 points (64 goals, 86 assists) across 93 games, including the playoffs. Connor McDavid finished a close second, and Colorado and Vegas each placed two players in the top ten scorers, more than any other team.

The top ten, by points

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(9, 5))
labels = scorers["player_name"] + " (" + scorers["team"] + ")"
ax.barh(labels[::-1], scorers["points"][::-1], color="#2c3e50")
ax.set_xlabel("Points")
ax.set_title("Top 10 Scorers, 2025-26 Season")
ax.spines[["top", "right"]].set_visible(False)
plt.tight_layout()
plt.show()
Figure 1: Top 10 point scorers, 2025-26 regular season and playoffs combined

The best record didn’t win the Cup

standings_query = """
SELECT
  team,
  COUNTIF(decision = 'W') AS wins,
  COUNTIF(decision = 'L') AS losses
FROM `maydaystats.nhl_stats.boxscores`
WHERE CAST(SUBSTR(CAST(game_id AS STRING), 5, 2) AS INT64) = 2
  AND position_group = 'goalie'
  AND decision IS NOT NULL
GROUP BY team
ORDER BY wins DESC
LIMIT 5
"""

standings = client.query(standings_query).to_dataframe()
standings
team wins losses
0 COL 58 16
1 CAR 55 22
2 DAL 52 20
3 TBL 51 28
4 MTL 50 25

Colorado had the best regular-season record in the league at 58-16, built in part on Nathan MacKinnon’s scoring, and Carolina wasn’t far behind. But the regular season and the playoffs are different tournaments. Colorado was eliminated in the second round, while Carolina kept going all the way to the Stanley Cup Final, where they met the Vegas Golden Knights.

final_query = """
WITH final_games AS (
  SELECT game_id, game_date, team, SUM(goals) AS team_goals
  FROM `maydaystats.nhl_stats.boxscores`
  WHERE CAST(SUBSTR(CAST(game_id AS STRING), 5, 2) AS INT64) = 3
    AND team IN ('CAR', 'VGK')
  GROUP BY game_id, game_date, team
)
SELECT
  game_date,
  MAX(IF(team = 'CAR', team_goals, NULL)) AS car_goals,
  MAX(IF(team = 'VGK', team_goals, NULL)) AS vgk_goals
FROM final_games
GROUP BY game_date
HAVING car_goals IS NOT NULL AND vgk_goals IS NOT NULL
ORDER BY game_date
"""

final = client.query(final_query).to_dataframe()
final
game_date car_goals vgk_goals
0 2026-05-04 3.0 3.0
1 2026-06-02 4.0 5.0
2 2026-06-04 4.0 3.0
3 2026-06-06 4.0 5.0
4 2026-06-09 5.0 3.0
5 2026-06-11 4.0 2.0
6 2026-06-14 3.0 0.0

The Final went six games, and four of them were decided by a single goal. Carolina closed it out on June 14 with a 3-0 shutout, taking the series 4 games to 2. Vegas rode Cam Hart the entire playoffs, all the way through the Final loss. Carolina’s path in goal was less steady: Frederik Andersen started most of the postseason, but after a Game 3 loss, Carolina turned to Brandon Bussi, who started and won Games 4, 5, and 6 to close out the series. Neither goalie led the league in wins during the regular season; that distinction was a near tie between Tampa Bay’s Andrei Vasilevskiy and Utah’s Karel Vejmelka, both at 39.

What’s next

This post covers the season at a high level: scoring, standings, and the playoff run. The same table supports much narrower questions too, like how a specific team’s goaltending held up across back-to-backs, or how a rookie’s production changed after the Olympic break. Those are posts for another day, now that a full season of clean data is sitting in BigQuery.

The pipeline code behind this post lives here.

Note

Like the baseball posts, this one uses Quarto’s frozen execution (freeze: true): the queries above ran once, locally, against BigQuery, and the deployed site reuses that committed output rather than re-querying on every build.