Prompted by both the 25th birthday of macOS (March 24th), and my buddy Kirk's prodding, my dormant A full history of macOS (OS X) release dates and rates post is coming back! After a long vacation, it's looking better than ever, and honestly, it's 10x more usable now.
Here's a behind-the-scenes look at what's changed during its 16 month vacation, and how it got there…

In addition to the cosmetic work done at Botox of Hollywood, here's what else has changed.
- All releases are now organized by major OS release—no more multi-row-spanning release dates. This means you can easily see all the releases for a given major OS version in one section. It also means that all the dates between releases are relevant.
- Within major releases, the main dot releases (.1, .2, etc.) are highlighted, and a key feature added is listed, until Apple didn't list any more for dot releases of that version.
- From macOS 14 onwards, links for main dot releases go to the general info page for the major release, until that page lists no more new features. Past that point, links go to the security update page for the release, if there is one. (If not, the fallback is the general info page.)
- Due to the new layout, the one date value that's been lost is the days between the final dot release of one OS and the initial release of the next major OS. But Apple's strategy of updating older OSes for quite a while has made that a less interesting data point anyway.
- You can expand and collapse each major OS section, so you're not overwhelmed by 288 table rows.
- As you scroll the table, if you have a major OS section open, its header will stick at the top of the table until you reach the next one.
- The OS headers show the code name, version number, and how many releases are in that section.
- Because each section now has consistent version numbers, they can be left aligned to make reading them much easier.
- The Size column has been banished. It hadn't been useful for years, especially as Apple now ships differently sized updates to different machines. It makes the table much cleaner, having it gone.
- The year-month-date columns have been combined, and listed in a standardized format. Again, this is cleaner, and much easier to read.
- Bonus feature #1: There's an Export button that exports a CSV of the entire table to your Downloads folder.
- Bonus feature #2: The large triangle in the black table header bar opens or closes all major sections with one click.
More exciting (at least to me) than the visual changes are the behind-the-scenes changes that will make keeping up with the macOS releases much easier for me—which is the only reason I revived this post.
Instead of a massive table of HTML (800 lines and counting!), the post is now entirely built by Javascript. Yes, this means the table isn't visible with Javascript disabled—but in today's web, there are a huge number of sites that don't function well—or at all—with Javascript disabled.
And for me, from a maintenance perspective, this was the only way forward. Using Javascript makes things so much easier on me, and is what let me bring this post back. But it's not just the table that benefits; all the variable data you see in the text (days since release, total releases, the most-recent version number, etc.) are also now calculated and filled in by the Javascript.
In the old model, I had to manually edit that massive table, add rows of raw HTML (with a lot of rowspan and colspan stuff thrown in), do various date calculations, and then load, edit, and reload to get it all right. And I had to edit the text to replace all the variable data.
With the new model, for each release, I just add a row to a table of values.
{ date:"2026-03-24", ver:"26.4", notes:"", url:"https://support.apple.com/en-us/122868" },
{ date:"2026-03-10", ver:"26.3.2", notes:"For MacBook Neo only.", url:"https://support.apple.com/en-us/122868" },
{ date:"2026-03-04", ver:"26.3.1", notes:"", url:"https://support.apple.com/en-us/122868" },
...
The Javascript then calculates all the date intervals, sorts OS releases into the proper sections, and generates all the HTML for the table and variable values in the text. If it's a major release, I have to add a similar row to one other section—so once a year, it's twice as much work :).
The other thing that took me a lot of time was updating the two graphs in Keynote, then clipping them out, cropping them properly in Acorn, saving them in web format, and uploading them. But this is the kind of thing Keyboard Maestro was created to handle, so I macro-ized that process. After updating the graphs, a hot key activates the macro and it does all the boring repetitive work to create and upload the graphs to the site.
How did I do all of this? Simple, I didn't (outside the Keyboard Maestro macro). I don't have that kind of Javascript skill, and learning it would have taken months, and still been nowhere near this sharp. Instead, I used Claude Code, and worked through the changes I wanted made to the table. (Clade Code also took care of finding and adding the 40+ updates that had been released since this post went on hiatus!)
If you're curious what a Claude Code session looks like, you can read my entire conversation with Claude—messages 16, 78, and 118 are where I ask for the big changes to be made; the rest is all adjustments to the resulting output.
Is it bad that I don't fully understand the Javascript that Claude Code wrote? At some level, you bet. But I know enough to see what it's doing, and the entire code base is only about 100 lines of code (plus all the table data), and it's just doing a lot of text manipulation.
I love the fact that Claude Code lets me do things that I simply wouldn't even contemplate before (more on that in a future post).
Between the new table layout and the Keyboard Maestro macro, updating the post should now take me only a few minutes…so please, enjoy the returned-from-vacation history of macOS releases!
I think the Javascript requirement is fine (especially since cloudflare is using it for bot rejection anyway) but it took just a few minutes and less than 5 requests for Claude to create a python script that takes your page and outputs a page that does not depend upon JS. It had to sacrifice the reveal/hide triangles though. I only did it because it seemed like the page was a bit slow to load and I wondered if straight html would be faster. It was, but asking Claude to optimize the page for load time also made a big difference too. FWIW, I often find I have to add a final clean-up and optimization step to any Claude code session. This is particularly true if the final result has taken a fair amount of back and forth to get to.
I had considered a static HTML page built off the JS version, but in my conversation with Claude, it said it wouldn't make any difference, and would actually be notably larger (with all the HTML for the table rows). The bulk of the page is the data for the 287 rows, and that's going to take time to load regardless of how it comes in. I did have it optimize (again), and it found one routine it could pull out, and changed how the listeners work. I'm not seeing super slow load times here; it seems about the same speed as the old page was.