DEV Community

Ted
Ted

Posted on • Originally published at tedagentic.com

Astro vs Lovable for SEO: Why Static Sites Win

My monitoring script fired at 3am. A content site I manage — the top-ranking page on that domain, the one its entire internal linking structure pointed to — had dropped out of the Google index entirely.

Not penalized. Not a manual action. Just gone — as if it never existed.

The diagnosis was quick. The site ran on a CSR stack — React, client-side rendered. Googlebot had visited, got a near-empty HTML shell, and moved on before JavaScript had a chance to build the DOM. At some point Google stopped waiting and dropped the page entirely.

The fix took less than an hour. Within a day or two it was back — and when it reappeared, it had moved from position 3 to position 2. Fixing the rendering issue properly actually moved it up.

That's the thing about CSR: it doesn't just risk a penalty. It quietly suppresses pages that should be ranking, and you won't know until they disappear.

The fix was a custom prerender layer — a static HTML snippet injected directly into the React root div under the id ssr-prerender. Googlebot sees real content immediately. Real users get the React app as normal, which replaces it on load. It works. But it's a patch, not a solution — something you bolt on after the fact, maintain separately, and have to remember every time you add a new page or change content.

Client-side rendering means the server returns an empty HTML shell. The browser runs JavaScript to build the page. That works for users. It's unreliable for crawlers — and the cost doesn't show up immediately. It shows up weeks later when pages quietly stop ranking.

Lovable is built for apps, not blogs. But plenty of people use it for content sites anyway — that's the mistake this post is about.

When I decided to build this blog — a place to document agentic AI workflows that I actually want people to find — I wasn't going to patch my way through it again.

The Tools I Looked At

Before landing on a stack, I mapped out the real options. Not just "what's popular" but what the actual tradeoffs are for a content site in 2026.

Lovable

Lovable.dev interface showing a prompt-to-app builder

Lovable is a prompt-to-app builder. You describe what you want, it generates a React codebase, you deploy. The UX is genuinely impressive for web apps — forms, dashboards, interactive tools.

Update (May 2026): Lovable shipped SSR as a first-class feature. New apps are now server-side rendered — Googlebot gets real HTML on the first request, the crawlability problem is gone for new projects. Existing apps get automatic pre-rendering at build time, which fixes the indexability issue without a DIY script.

The performance gap with SSG still exists. New Lovable apps ship a full React bundle and add server latency to every request — a static site serves pre-built HTML from a CDN edge node with no per-request compute. For a pure content blog where every page is the same for every visitor and LCP matters, SSG is still the faster path. But the hard wall that made Lovable the wrong choice for organic search is no longer there for new projects.

I still use it for clients who need web apps or interactive content. For a pure content site with no dynamic requirements, the SSG argument below still holds.

Cursor

Cursor is a VSCode fork with an embedded AI assistant — excellent for developers who want faster coding without giving up control. It doesn't pick a framework or manage deployments, so the SEO tradeoffs are entirely yours to manage.

What I Actually Use

My setup is deliberately boring:

  • ThinkCentre PC, bare metal Ubuntu, no cloud VM
  • Claude Code over SSH as the agent
  • Astro 4 — SSG, zero client JS by default
  • Vercel for deploy, auto-deploys on every push to master

Claude Code handles file editing, refactoring, and multi-step builds. I review diffs, approve writes, and push. The agent runs in my terminal — no subscription to a hosted IDE, no vendor controlling my environment.

Astro was the obvious framework choice once I ruled out React-based options. Every page is static HTML at build time. No JavaScript ships to the browser unless you explicitly add it. Googlebot sees exactly what a user sees, because there's no rendering step to skip.

The content schema is straightforward MDX files in src/content/posts/. Writing a new post is dropping a Markdown file and pushing. No CMS, no API calls, no paid tier. The overhead is real but front-loaded — you configure image optimization, redirects, and the content schema once. After that it doesn't move. That's a different kind of maintenance than patching a prerender layer every time you add a page.

Vercel deploy error during blog setup

Astro vs Lovable for SEO: The Real Comparison

This is the question that matters if you're using AI-assisted tools to build content sites.

Lovable is built for speed — you describe a UI, it ships React. That's genuinely useful for products, dashboards, anything interactive. But for a content site where organic search is the point, React's default rendering model is the wrong starting point.

Googlebot has a two-wave crawl model. First wave: fetch the raw HTML. Second wave: render JavaScript. The second wave happens on a delay — sometimes hours, sometimes days — and isn't guaranteed for every page on every crawl. For a new site or a page with low crawl budget, Google may only ever see the first wave. On a CSR site, that first wave is an empty shell.

Astro doesn't have this problem. The HTML is complete at build time — every page is just a file on disk, served directly. Googlebot gets the same document a user gets, on the first request, every time. An Astro page can be indexed the same day it's published. A Lovable page might take two weeks and a manual fetch request in Search Console to force the second render wave.

For a blog where every post is a potential traffic source, that's not a minor difference.

The SEO Tradeoff That Actually Matters

Here's the thing nobody says clearly: your platform choice is an SEO decision.

Every framework has a default rendering strategy. If that default is client-side, you're opting into a crawl risk. You can mitigate it, but you can't fully eliminate it — and every mitigation adds operational overhead.

To be precise: the risk is probabilistic, not guaranteed. High-authority domains with strong crawl frequency and deep internal linking can rank fine on CSR — Google's renderer has improved significantly, and a well-established site gives Googlebot reason to come back for the second wave. The risk is highest where the stakes are also highest: new sites, low crawl budget pages, and content that needs to index fast to catch a trend or a seasonal window. That's exactly where most content blogs live.

Static site generators like Astro, Eleventy, and Hugo don't have this problem. The HTML is there at request time, before any crawler or user arrives. There's nothing to render, nothing to wait for, nothing to patch around.

Beyond crawlability, static sites have compounding SEO advantages:

Speed. Astro ships zero JavaScript by default — the browser gets a finished HTML file and paints immediately. On a React CSR site, the browser downloads a JS bundle, parses it, executes it, then renders. That sequence adds hundreds of milliseconds to LCP on a cold load, and LCP is a Core Web Vitals signal Google uses as a ranking factor. My Astro blog consistently scores 95+ on PageSpeed Insights mobile. My client sites on CSR stacks rarely break 70 without active optimization.

Structured data. In Astro, JSON-LD schema lives in the base layout — defined once, present on every page at build time, no runtime dependency. On a CSR site, your structured data is injected by JavaScript. If the script errors, is blocked, or executes after Googlebot's render window closes, your schema is invisible. You won't see this failure in GSC until it's already cost you rich results.

Here's what that looks like in practice — the relevant slice of an Astro base layout:

---
const { title, description, canonicalURL } = Astro.props;
const schema = {
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": title,
  "description": description,
  "url": canonicalURL,
};
---
<head>
  <link rel="canonical" href={canonicalURL} />
  <script type="application/ld+json" set:html={JSON.stringify(schema)} />
</head>
Enter fullscreen mode Exit fullscreen mode

The canonical and structured data are rendered into the HTML at build time — no hydration, no runtime dependency, no silent failure.

Canonical URLs. Static generation makes canonicals deterministic. Every page has one URL, set at build time, baked into the HTML. CSR frameworks with dynamic routing can silently generate duplicate URLs under different query parameters — /posts/my-article and /posts/my-article?ref=homepage both return 200s, both get crawled, and both dilute the canonical signal unless you've explicitly handled it. With Astro, this class of problem doesn't exist.

For a content blog that needs to rank, none of this is optional. It's the baseline.

The Middle Path

Astro isn't the only way out of CSR. It's worth naming the alternatives so this doesn't read as "Astro or nothing."

Next.js gives you two paths to HTML-first rendering. output: 'export' is a full static export — no server features, no API routes, no ISR, just HTML files on disk with the same crawlability as Astro. getStaticProps is SSG inside a hybrid Next.js app that still has server routes, API endpoints, and ISR — more flexible, but you're choosing the rendering strategy per page deliberately rather than accepting a default. If you're already comfortable in Next.js, either path works. Astro islands (partial hydration) let you drop interactive React or Svelte components into otherwise static pages without shipping a full JS bundle. For a content site that needs one or two dynamic widgets, that's a clean solution.

The principle is the same regardless of which tool you pick: HTML-first by default, JavaScript added deliberately. Astro makes that the default. Next.js makes it possible but requires you to choose it. Lovable doesn't give you the option.

What I'd Tell Someone Starting Now

If you're building a web app — a tool, a dashboard, something with real interactivity — Lovable is a legitimate choice. Ship fast, iterate, worry about SEO when the product is solid.

If you're building a content site — a blog, a documentation site, a resource hub where organic traffic is the point — don't use a CSR framework as your foundation. The crawl risk is real, the fixes are patches, and you'll spend time maintaining workarounds that a static site simply doesn't need.

One honest limit worth naming: pure SSG pre-builds every page identically at deploy time. That works perfectly for content. It gets awkward when every page needs to render differently per user — a fully personalised feed, for example. For that you switch Astro to output: 'hybrid' or output: 'server' mode, which enables server-side rendering on specific routes while keeping everything else static. Auth and Supabase integration work fine in Astro either way — login flows, protected routes via middleware, user dashboards as islands. The constraint isn't "you can't do auth," it's "fully personalised page-level content at scale wants SSR, not SSG."

Astro is free, deploys to Vercel in one click, and handles all the SEO fundamentals out of the box. The learning curve is light if you know HTML and basic JavaScript. It's not the only answer — but for a new content site where every page needs to index fast, it's the lowest-friction path to getting that right.

Read part 2 to see how I built this blog in a single Claude Code session.

Part 3 covers the Lovable SSR update in detail — what pre-rendering for existing apps actually fixes, what it doesn't, and when the Astro argument still holds: Lovable Shipped SSR. Here's What That Actually Changes.

Top comments (0)