<?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: SAUNA EUROPE </title>
    <description>The latest articles on DEV Community by SAUNA EUROPE  (@saunaeurope).</description>
    <link>https://dev.to/saunaeurope</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%2F4244189%2F1757be8e-5e22-4c55-b86e-6ccdafb0073c.jpg</url>
      <title>DEV Community: SAUNA EUROPE </title>
      <link>https://dev.to/saunaeurope</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saunaeurope"/>
    <language>en</language>
    <item>
      <title>Lessons from moving a multilingual B2B site to Next.js: redirects, hreflang and old shop URLs</title>
      <dc:creator>SAUNA EUROPE </dc:creator>
      <pubDate>Sat, 14 Nov 2026 08:57:28 +0000</pubDate>
      <link>https://dev.to/saunaeurope/lessons-from-moving-a-multilingual-b2b-site-to-nextjs-redirects-hreflang-and-old-shop-urls-3c1o</link>
      <guid>https://dev.to/saunaeurope/lessons-from-moving-a-multilingual-b2b-site-to-nextjs-redirects-hreflang-and-old-shop-urls-3c1o</guid>
      <description>&lt;p&gt;When a site changes from an old web shop to a new framework, the visible design is the easy part. The invisible part is what hurts: old URLs, redirects and language versions. Here is what we learned while working on the Wood Architects website, a Lithuanian sauna manufacturer's B2B site built with Next.js and available in 15 languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Old URLs keep getting links for years
&lt;/h2&gt;

&lt;p&gt;The previous site was a shop with product URLs like &lt;code&gt;/shop/2-5-m-barrel-sauna-terrace&lt;/code&gt;. Years later, other sites still link to those addresses. A backlink report showed that these old URLs now redirect to a general category page instead of the matching product category.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; map every old URL to the closest equivalent page, not to a generic page. A redirect to an unrelated page is treated by search engines almost like a soft 404, and the link value is mostly lost.&lt;/p&gt;

&lt;p&gt;In Next.js you can handle this in &lt;code&gt;next.config.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  async redirects() {
    return [
      {
        source: '/shop/:slug*',
        destination: '/en/barrel-saunas',
        permanent: true,
      },
    ];
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Use &lt;code&gt;permanent: true&lt;/code&gt; so the response is a 301 (Next.js sends 308 for permanent redirects, which search engines treat the same way).&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Avoid redirect chains
&lt;/h2&gt;

&lt;p&gt;We found this path: &lt;code&gt;woodarchitects.eu&lt;/code&gt; -&amp;gt; &lt;code&gt;www.woodarchitects.eu&lt;/code&gt; -&amp;gt; &lt;code&gt;/en&lt;/code&gt;. That is two hops before the user sees a page. Each hop adds latency, and long chains can dilute signals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; redirect straight to the final canonical URL in one step. Pick one canonical host (with or without &lt;code&gt;www&lt;/code&gt;) and one default language path, then make every variant point there directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Multilingual sites need hreflang and consistent paths
&lt;/h2&gt;

&lt;p&gt;With 15 languages (&lt;code&gt;/en&lt;/code&gt;, &lt;code&gt;/de&lt;/code&gt;, &lt;code&gt;/fr&lt;/code&gt;, &lt;code&gt;/nl&lt;/code&gt;, &lt;code&gt;/da&lt;/code&gt;, &lt;code&gt;/sv&lt;/code&gt;, &lt;code&gt;/no&lt;/code&gt;, &lt;code&gt;/fi&lt;/code&gt;, &lt;code&gt;/is&lt;/code&gt;, &lt;code&gt;/es&lt;/code&gt;, &lt;code&gt;/pt&lt;/code&gt;, &lt;code&gt;/pl&lt;/code&gt;, &lt;code&gt;/it&lt;/code&gt;, &lt;code&gt;/el&lt;/code&gt;, &lt;code&gt;/lt&lt;/code&gt;), the main risks are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Language versions that do not point to each other with &lt;code&gt;hreflang&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A missing &lt;code&gt;canonical&lt;/code&gt; tag, so search engines pick the wrong version&lt;/li&gt;
&lt;li&gt;Language switcher links that go to the homepage instead of the same page in another language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep the same slug structure across languages where possible, and generate the language switcher links from the current page, not from a static list.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Check your backlinks after a migration
&lt;/h2&gt;

&lt;p&gt;A free backlink checker is enough to find this. Look for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Top linked pages that now return 404 or redirect somewhere unrelated&lt;/li&gt;
&lt;li&gt;Redirect chains on your most linked URLs&lt;/li&gt;
&lt;li&gt;Links to the non-canonical host (&lt;code&gt;www&lt;/code&gt; vs non-&lt;code&gt;www&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fixing these is often faster and cheaper than building new links.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Every old URL has a one-hop 301 to the closest matching page&lt;/li&gt;
&lt;li&gt;[ ] One canonical host and one default language path&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;hreflang&lt;/code&gt; and &lt;code&gt;canonical&lt;/code&gt; on every page&lt;/li&gt;
&lt;li&gt;[ ] Language switcher keeps the user on the same page&lt;/li&gt;
&lt;li&gt;[ ] Re-check backlinks and crawl errors a few weeks after launch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see the finished site, it is at &lt;a href="https://www.woodarchitects.eu/en" rel="noopener noreferrer"&gt;woodarchitects.eu&lt;/a&gt;. What was the hardest part of your last migration? Let me know in the comments.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
