Harky goes Astro ๐

TinaCMS is going default Astro(opens in a new tab) for their starter templates, so am I.
What I gained
- Production dependencies: from 26 to 18
- Dev dependencies: from 12 to 6
- React and Next packages: from 12 to 0
- Browser JavaScript: a React runtime down to one 16 KB bundle
The 16 KB is the view transitions router, so pages do not flash when you click between them. The rest of what you get is HTML that was built before you asked for it.
Why it was cheap
TinaCMS is headless. My content is MDX and JSON files sitting in my own GitHub repo under src/content/.
So what I migrated was the UI layer. The content stayed exactly where it was.
src/content/
posts/
poems/
pages/
tags/
authors/
global/Tina reads those through a schema in tina/. That schema never knew it was talking to Next.js, and it does not know it is talking to Astro now. It knows there is a collection called post with a title and a body. That is enough.
Why TinaCMS is going Astro
Matt Wicks wrote it up on the TinaCMS blog(opens in a new tab). His case is that more people clone the Astro starter than the Next.js one, and that Astro suits what Tina users are mostly building. The newer visual editing also uses data islands, so the whole page no longer has to behave like a React app.
He is clear that the Next.js starter stays. Nobody is being pushed anywhere.
Plus I respect Wicksy(opens in a new tab). He is undisputed leader of the Newy office and PO of TinaCMS ๐ซก.
How I did it
All of it with Claude Code.
- Put the Tina Astro starter(opens in a new tab) on a branch and left main branch alone until the very end. The old Next.js
app/andcomponents/tree got parked where we could both still read it while porting. - Rendered a single poem and opened
/adminto confirm I could still edit it live. - Brought the other collections across until the content matched what main was already serving.
- Rebuilt the design. Tokens, fonts, the shell around the page, accessibility.
- Rebuilt the pages themselves. Hero, blog, poems, tags, the 404.
- Let Vercel preview the branch. It builds a deployment for every branch, so the Astro version had a real URL with the real content.
- Merged. Vercel picked it up like any other deploy.
Each of those was its own commit, so when something broke I knew which commit broke it. Claude worked through the files and I read the diffs.
The work suits an agent because it is mechanical and the target shape was fixed.
It goes well with Tina because the schema is the contract. Claude never has to guess what a post is. It reads tina/collections/post.ts and the fields are right there.
What I kept for myself were the taste calls.
The one Vercel setting
Almost nothing changed on the Vercel side, which surprised me.
The one thing that did was the framework preset. Vercel had the project preset pinned to Next.js, so my Astro branch was being built as if it were a Next.js app. That does not work. Switching the preset was the whole step.
The other half is the @astrojs/vercel(opens in a new tab) adapter in astro.config.mjs:
export default defineConfig({
output: 'static',
adapter: vercel(),
});output: 'static' is the line that matters. Every page gets built once and served as a file.
Cloudflare, which I skipped
I looked at moving hosts at the same time. Astro is meant to run better on Cloudflare, and static output on their edge is close to the ideal case for a site like mine.
I didn't do it for a boring reason. It was not worth my time. Vercel already handles Astro fine, my domains and environment variables were already sitting there.
Maybe later.
Until then, enjoy hawky