My First Adventure with Astro: A Journey from Next.js
My First Adventure with Astro: A Journey from Next.js
I recently took a dive into Astro, it has been on my radar for a while now. Coming from a Next.js background, I was excited to try something new, especially for a single page static site.
Next.js is awesome, but it's a bit overkill for a simple static site. I wanted something that was simple to set up, fast to deploy, and easy to maintain. Of course, I could still go the old-fashioned way of just writing things in HTML and CSS, but at the same time this was a good opportunity to learn something new. So why not?
Why Astro?
Astro's approach to JavaScript is what initially caught my attention. We often throw JavaScript at every problem, whereas Astro takes a different stance - "Zero JavaScript by default."
What does this mean in practice? Well, imagine you're building a single page landing page. Most of your content is static - it doesn't need interactivity. With Next.js, you'd still be shipping a JavaScript bundle to handle routing and hydration, even for completely static pages. Astro, on the other hand, only ships HTML and CSS by default.
But don't get confused with this approach - Astro isn't anti-JavaScript. It's just smarter about it. If we need an interactive contact form or a dynamic chart? Astro lets you add JavaScript components exactly where you need them using "islands architecture." Each interactive component is isolated, meaning the rest of your page stays lean and fast.
This selective hydration approach means:
- Your initial page loads are blazing fast
- Your server costs might be lower (less bandwidth used)
- Better performance on mobile devices (less JS to parse and execute)
- Improved SEO (search engines love fast, lightweight pages)
Next.js vs Astro: My Take
Let's talk about how Astro compares to Next.js from my experience. Having used Next.js extensively, switching to Astro was an interesting journey.
The first thing you'll notice is the different philosophy. Next.js is built around JavaScript - it's in its DNA. You get all the React goodness, client-side routing, and a ton of built-in features. It's like having a Swiss Army knife for web development. Great for complex applications, but sometimes it feels like bringing a cannon to a knife fight.
Astro, on the other hand, feels more like traditional web development on steroids. It's refreshingly simple. You write your components in .astro
files, which took me a hot minute to get used to, but then it clicked. You can still use React components when you need them. It's not about choosing one or the other - it's about using the right tool for the job.
When it comes to development experience, both have their strengths. Next.js has this incredible hot reloading and TypeScript integration that just works. The ecosystem is massive, and you can find a solution for pretty much anything. But Astro? It's simpler. Less boilerplate, faster builds, and you're not locked into React. You can use Vue, Svelte, or anything else you want.
Performance is where things get interesting. Next.js does a great job optimizing your JavaScript, but you're still shipping the React runtime to your users. For a complex web app, that's fine - you need that interactivity. But for a simple landing page or a blog? That's where Astro shines. Your pages load instantly because they're just HTML and CSS. No JavaScript runtime, no hydration, no nothing - unless you explicitly ask for it.
The learning curve coming from Next.js is surprisingly gentle. Yes, you'll need to shift your mindset a bit. You'll start thinking more about what actually needs JavaScript and what doesn't. But in a way, it feels like going back to basics - in a good way.
Setting Up with devenv/nix
Since I use devenv/nix for my development environment, setting up an Astro project was an easy process. The devenv/nix setup is simple and minimal:
{ pkgs, ... }:
{
packages = with pkgs; [
nodejs_20
nodePackages.pnpm
nodePackages.wrangler
];
scripts = {
dev.exec = "pnpm dev";
build.exec = "pnpm build";
preview.exec = "pnpm preview";
};
}
The same setup works on MacOS, Linux, local env or server. Just need to run these two commands:
direnv allow
devenv up
No more "it works on my machine" problems!
Tailwind CSS Integration
Adding Tailwind to Astro was surprisingly simple. Just install the integration:
pnpm astro add tailwind
You get all the Tailwind goodness with zero config. The integration with Astro's templating feels natural, and the CSS output is optimized automatically.
Cloudflare Pages and Workers
Deployment to Cloudflare Pages
Deploying to Cloudflare Pages was pretty easy as well. The astro.config.mjs
setup is minimal:
export default defineConfig({
output: "server",
adapter: cloudflare(),
integrations: [tailwind()]
});
Setting Up Email with Cloudflare Workers
I've been using Cloudflare Workers for a while now, so integrating it with Astro was pretty straightforward. Workers are pretty good for handling any server-side logic - they're fast, reliable, and the free tier covers most small projects easily.
I wanted to test out how Astro handles dynamic features, so I decided to add a contact form to the site. It's a good way to see how Astro works with external services and client-side interactions. Since I already had Workers set up for the API endpoints, adding the email functionality was simple enough. Workers let you handle both the API endpoints and the email sending in one place, which keeps things clean and simple.
A Few Gotchas Along the Way
The transition to Astro wasn't all smooth sailing. Partial hydration is probably the biggest mental shift - you need to explicitly tell Astro which components need JavaScript. At first, I kept forgetting to add the client:load
directive to my interactive components and wondering why they weren't working. But once you get into the habit, it actually makes you think more carefully about where you really need that JavaScript.
Understanding Astro's Islands
One last note about Astro's most interesting features - the island architecture. Think of your webpage as a static ocean of HTML, and your interactive components as islands of JavaScript. Each island is independent, which means you can have a React island here, a Vue island there, and the rest of your page stays static and fast.
In practice, this means you can do something like this: your navigation menu could be a React component (because you need that smooth mobile menu animation), your contact form could be a Vue component (because that's what your team prefers for forms), and everything else - your blog posts, your about page, your footer - can be just plain HTML. No JavaScript overhead, no framework tax.
The way Astro handles this is pretty clever. You just add a directive like client:load
or client:visible
to your component, and Astro takes care of loading the JavaScript only when it's needed. Want that heavy chart component to load only when it's scrolled into view? Just use client:visible
. Need that contact form to be interactive immediately? Use client:load
. It's like having a dimmer switch for JavaScript instead of just an on/off button.
Final Thoughts
Would I use Astro again? Absolutely! The combination of Astro + Tailwind + Cloudflare feels like a winning stack for static sites, especially for landing pages. While Next.js is still great for complex applications, Astro hits a sweet spot for content-focused sites.