<?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: K. E. Atak</title>
    <description>The latest articles on DEV Community by K. E. Atak (@atakee).</description>
    <link>https://dev.to/atakee</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%2F1002400%2Fde76a9fc-e176-45f3-884a-f8a206c4f37b.jpg</url>
      <title>DEV Community: K. E. Atak</title>
      <link>https://dev.to/atakee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/atakee"/>
    <language>en</language>
    <item>
      <title>Migrating my portfolio from Next.js + Sanity to Astro 5</title>
      <dc:creator>K. E. Atak</dc:creator>
      <pubDate>Wed, 19 Aug 2026 13:25:09 +0000</pubDate>
      <link>https://dev.to/atakee/migrating-my-portfolio-from-nextjs-sanity-to-astro-5-475m</link>
      <guid>https://dev.to/atakee/migrating-my-portfolio-from-nextjs-sanity-to-astro-5-475m</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ercan-atak.de/blog/migrating-portfolio-nextjs-sanity-to-astro/" rel="noopener noreferrer"&gt;ercan-atak.de&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I moved my portfolio from &lt;strong&gt;Next.js 14 + Sanity&lt;/strong&gt; to a &lt;strong&gt;static Astro 5&lt;/strong&gt; site, and the short version is: the new site ships almost no JavaScript, has no external CMS, and drops every third-party network call that used to make GDPR compliance a chore. Content that once lived in a hosted Sanity dataset now lives in the repo as MDX and JSON, validated at build time. The only interactive JavaScript that reaches the browser is four small Svelte islands; everything else is server-rendered HTML with zero client runtime.&lt;/p&gt;

&lt;p&gt;This post is the honest account of why I did it and what the trade-offs were — not a "Framework A beats Framework B" pitch. If you run a content-light personal site on a React meta-framework and a hosted CMS, most of this will apply to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why leave Next.js + Sanity at all?
&lt;/h2&gt;

&lt;p&gt;The old stack worked. The problem was that it was &lt;strong&gt;heavier than the job required&lt;/strong&gt;. A portfolio with a handful of blog posts, some project write-ups, and image galleries doesn't need a React runtime on every page, and it doesn't need a hosted headless CMS with its own API, auth, and monthly moving parts.&lt;/p&gt;

&lt;p&gt;Three things pushed the migration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript I wasn't using.&lt;/strong&gt; Next.js hydrates pages by default. Most of my pages are text and images — there was nothing to hydrate. I was paying a runtime tax for interactivity that only existed in two or three places.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A CMS I was renting for content I owned.&lt;/strong&gt; Sanity is a good product, but my content is a dozen files. Putting them behind an external API meant a network dependency at build time and a second place to reason about schemas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GDPR overhead.&lt;/strong&gt; Operating a site under a real name from Germany means an &lt;em&gt;Impressum&lt;/em&gt; and a &lt;em&gt;Datenschutzerklärung&lt;/em&gt;, and every third-party call you make is something you have to disclose and justify. Fewer external calls is not just faster — it's less legal surface.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The architecture: server-first, islands rarely
&lt;/h2&gt;

&lt;p&gt;Astro's model is the whole reason this works. Pages are &lt;code&gt;.astro&lt;/code&gt; components that render to HTML at build time and ship &lt;strong&gt;zero JavaScript&lt;/strong&gt; unless you explicitly opt in. Where I genuinely need the browser — a live clock, a mobile menu, the contact form, a custom cursor — I use a &lt;strong&gt;Svelte 5 island&lt;/strong&gt; hydrated with the narrowest directive that fits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;client:only&lt;/code&gt; for things that depend entirely on browser APIs (localStorage, &lt;code&gt;document&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client:visible&lt;/code&gt; to defer a below-the-fold form until it scrolls into view,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client:idle&lt;/code&gt; for non-critical touches that can wait for the main thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is four islands total. Every other component is static HTML. There is no framework runtime on the critical path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content collections replaced the CMS
&lt;/h2&gt;

&lt;p&gt;Instead of Sanity, content lives in &lt;strong&gt;Astro content collections&lt;/strong&gt;: MDX for blog posts, JSON for the photography rolls, testimonials, and paintings. Each collection has a &lt;strong&gt;Zod schema&lt;/strong&gt;, so a missing field or a wrong type fails the build instead of shipping broken. Adding a post is creating a file with the right frontmatter — it appears automatically, sorted and validated.&lt;/p&gt;

&lt;p&gt;For the parts I want to edit without touching the repo, I wired a &lt;strong&gt;git-based CMS&lt;/strong&gt; (Sveltia) that commits Markdown and JSON straight to GitHub. It's a thin editing layer over the same files — not a separate content backend. The source of truth is still the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GDPR wins were the real payoff
&lt;/h2&gt;

&lt;p&gt;This is the part I underestimated. Going static let me remove entire categories of compliance risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted fonts.&lt;/strong&gt; No Google Fonts CDN. A German court (LG München I, 3 O 17493/20) ruled that loading Google Fonts from Google's servers transmits a visitor's IP to the US without consent — and opportunistic claimants still send €100-per-pageview letters over it. I self-host the two font families locally; the browser never talks to Google.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookieless analytics.&lt;/strong&gt; I use a privacy-respecting, cookieless analytics setup with no persistent identifiers, which falls outside the German cookie-consent rules (§ 25 TDDDG). The site is genuinely cookie-free, so there is &lt;strong&gt;no cookie banner&lt;/strong&gt; — and adding one would be pure UX cost with zero legal upside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer processors to disclose.&lt;/strong&gt; Every third-party call is a line in the privacy policy. Static hosting plus local content means the list is short and honest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is exotic. It's what you get "for free" when the default is to send nothing to the browser and nowhere off-origin.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I gave up
&lt;/h2&gt;

&lt;p&gt;Honesty section, because every migration has one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No on-demand rendering.&lt;/strong&gt; Static output means content updates require a rebuild. For a portfolio that's a non-issue; for a news site it would be. Where I need freshness (image EXIF, a visitor counter), I fetch at build time or hydrate a tiny island.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A migration is still work.&lt;/strong&gt; Moving content out of Sanity, rebuilding every page as &lt;code&gt;.astro&lt;/code&gt;, and rewiring the few interactive bits took real effort. The payoff is ongoing (every page load, forever), but the cost is upfront.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React muscle memory.&lt;/strong&gt; Astro and Svelte are not React. The concepts transfer, but the syntax and the hydration model don't. Budget a little ramp-up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Would I recommend it?
&lt;/h2&gt;

&lt;p&gt;For a &lt;strong&gt;content-light, interaction-light personal site&lt;/strong&gt; — a portfolio, a résumé site, a small blog — yes, without hesitation. The static-by-default model matches the shape of the work, the zero-JS baseline is a real performance and privacy win, and owning your content as files in a repo is simpler than renting it from an API.&lt;/p&gt;

&lt;p&gt;For an app with real interactivity on most pages, the calculus changes and a framework that hydrates by default may earn its keep. The point isn't that static wins — it's that &lt;strong&gt;the runtime should match the page&lt;/strong&gt;. My pages are mostly text and photographs, so mostly they ship none.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This whole site is the reference implementation. If you're curious how a specific piece works, the &lt;a href="https://ercan-atak.de/work/" rel="noopener noreferrer"&gt;work section&lt;/a&gt; and the rest of the &lt;a href="https://ercan-atak.de/blog/" rel="noopener noreferrer"&gt;journal&lt;/a&gt; go into the details — and &lt;a href="https://ercan-atak.de/colophon/" rel="noopener noreferrer"&gt;the colophon&lt;/a&gt; explains how the site itself is built.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>astro</category>
      <category>webdev</category>
      <category>gdpr</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
