Astro
-
SvelteKit vs Astro: How I Choose in 2026
If you’ve followed my blog over the past few months, you know I’ve spent a lot of time digging into Svelte 5. Runes completely changed the way I think about reactivity, and SvelteKit is still one of the most elegant frameworks I’ve used for building genuinely interactive web apps.
So lately I’ve been thinking about: when does it make sense to use Astro instead of SvelteKit?
The honest answer is that they’re not really competing, or at least they didn’t used to be. Both frameworks are excellent, and historically they solved two pretty different problems. That line has gotten blurrier lately, but the old split is still the best starting point I’ve got. After building so many things with Astro’s recent updates, here’s how I think about picking one in 2026.
SvelteKit Is for Apps
When you’re building a dashboard, a complex SaaS tool, or anything where state needs to persist across a lot of dynamic route changes, SvelteKit is hard to beat.
SvelteKit assumes your app is going to do a lot of client-side work, and it leans into that. Form actions, nested layouts, complex data loading, it makes all of it straightforward. Combine the routing with Svelte 5’s runes and you get a developer experience that feels like writing plain JavaScript, except the reactivity just happens.
My rule of thumb: if the user is going to be clicking around, dragging things, and holding a long-lived session, I reach for SvelteKit.
Astro Is for Content
Astro comes at the web from the opposite direction. The core philosophy is “zero JS by default,” and it means it.
If you’re building a blog, a marketing site, documentation, or a storefront where the whole point is getting content in front of the reader as fast as possible, Astro wins. Its Islands Architecture ships raw, fast HTML and only hydrates the specific interactive pieces that actually need JavaScript. The result is a site that’s quick out of the box without you having to fight for it.
I should be fair, though: Astro hasn’t stayed in its lane. Recent releases have pushed it toward more dynamic, app-like territory with Server Islands, type-safe Actions, and a sessions API. The “content only” box doesn’t hold the way it did a year ago, and you can build genuinely interactive things in Astro now if you want to.
So I’d put it this way instead: as a rule of thumb, if it feels more like a website than a piece of software, that’s still where Astro shines.
You Don’t Actually Have to Choose
Here’s the the fun part, Astro has first-class support for Svelte.
You don’t give up Svelte to use Astro. Say I’m building a content-heavy site but I need one genuinely complex interactive piece, like a calendar component. I can write that calendar in Svelte, drop it into an Astro page, and tell Astro to hydrate only that component with a
client:loaddirective.You get the performance of a static or server-rendered Astro page, plus the developer experience of writing Svelte for the bits that need to be interactive. That’s a really good deal.
So Which One?
There’s real overlap now, so treat this as a default rather than a law. But it mostly still comes down to one question: are you building software or a website?
- Reach for SvelteKit when you’re building an application. If it feels like software, this is your tool.
- Reach for Astro when you’re building a content site. If SEO, initial load speed, and reading experience are the priorities, let Astro do the heavy lifting and sprinkle in Svelte components where you need them.
Pick the framework that matches the kind of thing you’re building, lean on the overlap when it helps, and don’t agonize over it. Either way you’re starting from a good place.
What are you reaching for first when you spin up a new project these days?
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
Astro javascript svelte Web development Sveltekit Frameworks
-
Semantic Docs Spring Update: Astro 6, Auto-Releases, npm
The last two months on Semantic Docs have mostly been maintenance work, but a few things I wanted to talk about. I pushed through a major framework upgrade, swapped out a vendored library for a real published package, and finally automated the release pipeline. Five tagged releases later, here’s where we are.
The Headlines
- Upgraded to Astro 6
- Switched from a vendored logger to the published
logan-loggernpm package - Shipped an auto-release workflow driven by Conventional Commits
- Three rounds of dependency updates plus a security-focused sweep
- Five tagged releases,
v1.3.3throughv1.5.0
Astro 6
The Astro 6 upgrade was easy. Semantic Docs runs a hybrid setup, static article pages plus a server-rendered search endpoint, and that part barely needed any attention. Most of the work was in the dependency layout, not the application code.
One note if you’re forking or syncing this theme: if you’re upgrading from
v1.3.5or earlier (anything pre-Astro-6, which landed inv1.4.0), delete yournode_modulesand your lockfile and do a clean install. Skip that step and you’ll get weird errors that look like your code is broken when it’s really just leftover state.A Real npm Package Instead of a Vendored Logger
For a while, the project was using a logger I wrote to experiment with publishing to both npm and JSR. It was a useful exercise. I wanted to see what a clean foundational package looked like across both registries, and I think it turned out well.
But for this repo, I wanted consistency over experimentation. So I swapped the vendored copy for the published
logan-loggernpm package. Behavior is the same, the surface area is the same, it’s just back on the npm registry.Automated Releases
I’ve liked using Conventional Commits to drive automated releases. When a PR merges to main, the workflow figures out the next version from the commit messages, tags it, and publishes a GitHub release with a generated changelog.
The commit type determines the version bump.
feat:bumps the minor,fix:bumps the patch, breaking changes bump the major. The changelog falls out of the same metadata. More automation here the better.If you’ve been on the fence about Conventional Commits, this is the use case that sold me.
What’s Next: Embedding Quality
The reference implementation uses TEI for search embeddings, and that’s been fine. But “fine” is not the same as “good,” and I want to actually compare quality across providers before I commit to anything long term.
Two I want to test:
- Jina (now owned by Elastic)
- Mistral, which has been putting out genuinely strong embedding models
The goal is to run the same corpus through each, evaluate the search results, and figure out which one earns a highlight. Whatever I learn from that work will get folded back into the open source Semantic Docs repo so anyone running their own instance can make an informed choice instead of just trusting my defaults.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Routing in SvelteKit vs Next.js vs Astro
Continuing my series on Svelte, I want to dig into how SvelteKit handles routing and how it compares with Next.js and Astro. These are the frameworks I am most familiar with, so apologies if you wanted a different framework.
Let’s start with everybody’s favorite topic: routing. Okay, maybe I’m the only one excited about this, but stick with me.
Astro: The Traditional Approach
Astro’s routing feels the most traditional of the three. You have a
src/pages/directory, and the file name is the route. Sosrc/pages/dashboard.astromaps to/dashboard. If you’ve worked with PHP or other languages with file-based routing, this will feel immediately familiar.Inside the
.astrofile, you separate your backend logic at the top of the file with---fences. That code runs entirely on the server, and everything below is your HTML template. Clean and straightforward.Next.js: Folder-Based with the App Router
Next.js (the current versions, at least) uses the App Router. The structure is folder-based:
app/dashboard/page.tsxmaps to/dashboard. The key difference from Astro is that the folder name determines the route, but the file must always be calledpage.tsx.By default, everything in the
appdirectory is a server component, meaning it runs on the server. If you want client-side interactivity, you explicitly add"use client"at the top of the file. You can also set"use server"if you want to be explicit, but it’s the default. I think Next.js does a really good job of making it clear what runs where.SvelteKit: Convention Over Configuration
SvelteKit also uses folder-based routing, similar to Next.js. The structure is
src/routes/dashboard/, but instead ofpage.tsx, SvelteKit uses a reserved+prefix for its special files:+page.svelte— Renders on the server, then hydrates on the client+page.server.ts— Runs only on the server (data loading, form actions)+server.ts— A raw API endpoint with no UI
There’s no
"use client"or"use server"directive. The file naming convention itself tells SvelteKit what should run where. If you fetch a database record in+page.server.ts, that data is returned as an object, fully typed, and available in your+page.sveltevia the$propsrune. It just works.The Case for Standard File Names
I can see if some people get annoyed that every route has files named
+page.svelteand+page.server.ts. The files will all look the same in the IDE, but there’s a real advantage here: you can group all related components in the same route folder.For example, if you’re building a dashboard, you can keep your
DashboardChart.svelte,DashboardFilters.svelte, and other components right alongside your+page.svelteand+page.server.ts. You always know which file is the route entry point, which handles server logic, and which are supporting components. It encourages logical grouping instead of scattering related files across the project.Quick Comparison
Feature Astro Next.js SvelteKit Route structure File name = route Folder + page.tsxFolder + +page.svelteServer/client split ---fences"use client"directiveFile naming convention API routes src/pages/api/app/api/route.ts+server.tsDefault rendering Server Server Server + hydration All three frameworks use file-based routing, but they each have a slightly different philosophy about how to organize and separate concerns. Astro keeps it simple with traditional file mapping. Next.js gives you explicit directives. SvelteKit leans on naming conventions to keep things clean.
I think I can get used to the
+prefix convention in SvelteKit. The type safety between your server file and your page component is nice.Next up in the series, I’ll dig into how each framework handles data loading and forms.
-
Introducing EmDash — the spiritual successor to WordPress that solves plugin security
Today we are launching the beta of EmDash, a full-stack serverless JavaScript CMS built on Astro 6.0. It combines the features of a traditional CMS with modern security, running plugins in sandboxed Worker isolates.
-
EmDash is a full-stack TypeScript CMS based on Astro; the spiritual successor to WordPress - emdash-cms/emdash
-
It’s always some weird networking thing. Switched an internal Astro site from PNPM to Bun last night, didn’t test it before bed. Woke up to port 4321 not binding; dev server wouldn’t start. Turns out it randomly decided to only bind on IPv6 overnight. Had to explicitly tell it to bind on IPv4. Why is it always networking?