All Posts
Cloud & DevOps

Four Version Dates Land by 12 November. Keep a Ledger.

Next.js 15, Node 24 and Postgres 14 all change support status within weeks. A one-table support-window ledger turns upgrades from a debate into a date.

8 min read

Between 20 October and 12 November 2026, four dates change the support status of the three components most SaaS teams run on. Node.js 24 leaves Active LTS, Next.js 15 leaves Maintenance LTS, Node.js 26 enters LTS, and PostgreSQL 14 receives its last fix. None of these needs a project. All of them need an owner and a date. I keep a support-window ledger: one row per version line, with an end date and a lead time, and I move when a row crosses its lead-time line rather than when a changelog gets me excited. A support-window ledger is a table of every runtime, framework, and database a company depends on, with the date each stops receiving security fixes and the lead time needed to move off it.

Why this matters now

Start with the framework. Next.js's support policy gives Active LTS from release until the next major ships, and Maintenance LTS for two years after the initial release, with only critical bug fixes and essential security updates. Next.js 15 shipped on 21 October 2024, so by that rule its security coverage ends on 21 October 2026, which is also what endoflife.date lists. Versions 14 and older already receive no security updates at all.

The tempo matters as much as the date. Next.js published an August security release on 25 August covering two critical-severity issues, an out-of-band update for a critical upstream issue on 22 September, and on 30 September a further release that fixed one high-severity and five medium-severity issues, plus one low, in 16.3.8 and 15.5.27. That is three security releases in about five weeks. A team that is two minors behind turns each of those into an emergency; a team on the latest patch of a supported line turns each into a routine bump.

The runtime and the database have their own clocks. Per the Node.js release schedule, Node 24 moves from Active LTS to Maintenance on 20 October, Node 26 becomes LTS on 28 October, Node 22 reaches end of life on 30 April 2027, and Node 20 already did on 30 April 2026. PostgreSQL 14's final release is 12 November, per the versioning policy; I covered what to do about that in a separate post.

What the ledger looks like

The ledger is deliberately boring. Each row is a version line, not a service, and carries three facts: when fixes stop, how many days I need to move off it, and who owns the move. Everything else is derived. Here is the whole thing as a small script I keep in the repository, so the table is reviewed in a pull request like any other change.

// support-ledger.ts: one row per version line, not per service.
type Row = { line: string; endOfFixes: string; leadDays: number; owner: string }

const ledger: Row[] = [
  { line: "next@15", endOfFixes: "2026-10-21", leadDays: 30, owner: "web" },
  { line: "node@22", endOfFixes: "2027-04-30", leadDays: 14, owner: "platform" },
  { line: "postgres@14", endOfFixes: "2026-11-12", leadDays: 90, owner: "data" },
]

const DAY = 86_400_000

export function status(row: Row, today = new Date()) {
  const daysLeft = Math.ceil((Date.parse(row.endOfFixes) - today.getTime()) / DAY)
  if (daysLeft < 0) return { ...row, daysLeft, state: "UNSUPPORTED" }
  if (daysLeft <= row.leadDays) return { ...row, daysLeft, state: "MOVE NOW" }
  if (daysLeft <= row.leadDays * 2) return { ...row, daysLeft, state: "SCHEDULE" }
  return { ...row, daysLeft, state: "OK" }
}

console.table(ledger.map((r) => status(r, new Date("2026-10-05"))))

Run against the date in the last line, it reports Next.js 15 and Postgres 14 as MOVE NOW and Node 22 as OK. The interesting number is the lead time, because that is where judgement lives. These are my working numbers, not measurements: about two weeks for a runtime LTS bump, a month for a framework major that touches a CMS or an auth library, and a quarter for a database major that needs a rehearsed revert. Change them to match what your own last upgrade actually cost. The point is that the state is computed from two dates and one honest estimate, so nobody has to win an argument to schedule the work.

What this changes for a founder or CTO

Version currency is mostly a decision cost, not an engineering cost. The unscheduled version is expensive because it arrives as an incident: a critical advisory, a customer security questionnaire, a dependency that stops installing on an end-of-life runtime. The scheduled version is cheap because it lands on a Tuesday with a rollback plan. A ledger does not reduce the engineering effort by much. It moves the effort from a day you did not choose to a day you did.

It also makes the cost visible to someone who does not read changelogs. When a non-technical founder can see that Postgres 14 has 38 days of fixes left and a 90-day lead time, the conversation stops being about whether upgrades are worth it and becomes a question about which week.

A framework with three rules

  1. Track version lines, not services. The number of upgrade decisions is set by how many independent version lines you carry, not by how many services you run. A monorepo of around a dozen services, like the one I lead at Keaz, can share one Node line and one Postgres line, which is one row each.
  2. Move by the end date minus the lead time, and not earlier than about ninety days after a new major ships unless it fixes a constraint you actually have. Earlier is a bet on someone else's release quality, because the bugs early adopters find are fixed in the first minor releases, not in the announcement.
  3. Separate patching from upgrading. Patches on a supported line, such as the 15.5.27 fix above, ride a continuous budget and should be boring. Majors ride the ledger. Mixing the two is how a security patch ends up blocked behind a framework migration.

For the four dates in this post, the comparison looks like this:

  • Next.js 15: fixes end 21 October 2026. Move to the 16 line, which is Active LTS.
  • Node.js 22: fixes end 30 April 2027. It can wait; Node 26 becomes LTS on 28 October and its dependencies will settle first.
  • Node.js 24: stays supported until April 2028 and enters Maintenance on 20 October. No action beyond noting the date.
  • PostgreSQL 14: final fix 12 November 2026. Already inside most teams' lead time.

My perspective

Staying current is not a virtue. Being inside a support window with a scheduled exit is. I would rather run a Maintenance LTS line deliberately, with its end date in a table and a named owner, than chase every major release the week it ships. That position has a cost, and I want to state it: the Maintenance line buys you time, and then you repeat the move sooner than someone who jumped early. For a small team I think that trade is correct, because the thing a small team cannot afford is surprise. The shape of the work at Keaz is why I hold this view: a monorepo of around a dozen services means a runtime bump is one change in one place, so the real risk was never the typing. It was forgetting the date.

What to do this quarter

Put the ledger in the repository this week and fill it with what you actually run, including the lines nobody thinks about, such as the Docker base image and the CMS. Patch Next.js to the latest release of your supported line today, then schedule the 15 to 16 move before 21 October if you are still on 15. Leave Node where it is until 26 has been LTS for a month. If you want help sizing the lead times for your own stack, my services page describes how I work with teams as a fractional CTO, and I would rather you started with a ledger than a rewrite. For the Keaz background behind this approach, see the Keaz case study.

Put an owner and a date on every version

If your ledger is empty, or you cannot tell which rows are already red, book a time and we will build the first version together.

#Technical Debt#Next.js#Node.js#Postgres#Fractional CTO