<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Max Tesla</title>
    <description>The latest articles on DEV Community by Max Tesla (@maxtesla).</description>
    <link>https://dev.to/maxtesla</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4031091%2F577f905c-db77-44ed-995f-9c8e7d5b0407.png</url>
      <title>DEV Community: Max Tesla</title>
      <link>https://dev.to/maxtesla</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxtesla"/>
    <language>en</language>
    <item>
      <title>Why I picked Astro over Next.js for my site</title>
      <dc:creator>Max Tesla</dc:creator>
      <pubDate>Wed, 15 Jul 2026 22:54:47 +0000</pubDate>
      <link>https://dev.to/maxtesla/why-i-picked-astro-over-nextjs-for-my-site-2pf8</link>
      <guid>https://dev.to/maxtesla/why-i-picked-astro-over-nextjs-for-my-site-2pf8</guid>
      <description>&lt;p&gt;I've just launched my first personal site. I almost built it in Next.js anyway.&lt;/p&gt;

&lt;p&gt;Not from habit - I just knew Next.js by reputation. Huge community, shadcn/ui ecosystem, every tutorial assumes it. It's the gravitational default for anything frontend. I stopped myself, thought about what I actually needed, and picked &lt;a href="https://astro.build" rel="noopener noreferrer"&gt;Astro&lt;/a&gt; instead. Writing this down so future-me doesn't skip that step next time.&lt;/p&gt;

&lt;p&gt;This site is a markdown renderer with opinions. Five pages, zero forms, no auth, no database, no mutations. The interactive surface area is a theme toggle and some scroll-driven CSS.&lt;/p&gt;

&lt;p&gt;Astro is a markdown renderer with opinions. Next.js is a backend framework that can also render markdown.&lt;/p&gt;

&lt;p&gt;Using Next.js here would be like hiring a full-stack team to run a one-person blog. You get everything Next ships - middleware, route handlers, server actions, ISR, edge runtime, parallel routes - and use almost none of it. Every dependency you don't use still costs build time, bundle size, and decision fatigue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Astro gives me
&lt;/h2&gt;

&lt;p&gt;Zero JS ships unless I opt into a client island. My hero's skill-tag animation is &lt;code&gt;animation-timeline: scroll()&lt;/code&gt; - pure CSS, no React, no hydration, no TTI cost. The property has &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline" rel="noopener noreferrer"&gt;limited cross-browser support&lt;/a&gt; as of April 2026 - Chrome and Edge, not yet Baseline - so I wouldn't reach for it in a product.&lt;/p&gt;

&lt;p&gt;Content collections give typed frontmatter via Zod schemas. I write &lt;code&gt;content.config.ts&lt;/code&gt; - twelve lines, shown below - drop an &lt;code&gt;.mdx&lt;/code&gt; file in &lt;code&gt;src/content/posts/&lt;/code&gt;, and it's typed end-to-end. No custom loader, no API route, no database client.&lt;/p&gt;

&lt;p&gt;Shiki is the default code highlighter. Dual-theme light/dark takes one config block in &lt;code&gt;astro.config.ts&lt;/code&gt; and a CSS media query - no PrismJS, no rehype chain, no copy-pasting highlight.js CSS from 2018. MDX integrates via &lt;code&gt;@astrojs/mdx&lt;/code&gt; if I need React components inside a post.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm giving up
&lt;/h2&gt;

&lt;p&gt;Server actions - don't need them, the site has no mutations. Dynamic routes at request time - everything pre-renders at build, and Astro supports API routes if that changes. The cost is muscle memory: Astro's &lt;code&gt;.astro&lt;/code&gt; syntax is new. First hour felt like JSX with amnesia. Hour two felt like HTML that finally got proper imports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I'd still reach for Next.js
&lt;/h2&gt;

&lt;p&gt;The admin dashboard, full-stack e-commerce, anything with real auth flows and a database - Next.js, no debate. Or Hono with a lighter frontend for API-first products. The question is always the same: where does the complexity live? If it's in content, pick a content framework. If it's in mutations and state, pick a full-stack framework.&lt;/p&gt;

&lt;p&gt;"Just use Next.js for everything" is a reasonable default. It works, it ships, you don't have to think. The cost is that you stop matching the tool to the problem, and that atrophies judgment. Picking Astro for this site took 20 minutes. Those 20 minutes are the whole point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// content.config.ts — the entire posts layer for this site.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineCollection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;astro:content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;glob&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;astro/loaders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineCollection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/*.{md,mdx}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/content/posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt;
    &lt;span class="na"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Twelve lines. Add a file, get types automatically.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>nextjs</category>
      <category>sideprojects</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
