Domain redirects with Next.js (language depended or general)

Hi!

I’m trying to setup a multi-locale next.js website on Netlify. The website has two domains configured and I assumed that Automatic Locale Detection should work fine with Domain Routing (it does on Vercel), but no redirect happens on Netlify.

This wouldn’t be a big issue because in the end it’s just a language based redirect on / so I started looking into Netlify redirect definitions. First using the _redirects file, but no matter what I’m doing the redirects are not picked up (e.g. checking the total number of redirect rules in the deploy output). So I moved to the netlify.toml definitions, which are picked up fine during the deploy. But they also don’t seem to work. Not just language based redirects but pretty basic rules like:

[[redirects]]
  from = "https://www.example.com"
  to = "https://example.com"
  status = 301
  force = true

[[redirects]]
  from = "http://www.example.com"
  to = "https://example.com"
  status = 301
  force = true

[[redirects]]
  from = "https://www.example.com/"
  to = "https://example.com"
  status = 301
  force = true

[[redirects]]
  from = "http://www.example.com/"
  to = "https://example.com"
  status = 301
  force = true

(To my understanding the trailing slash version should not be required, but I added it just to be on the safe side.)

The www page still happily returns a 200 OK response and renders the main page:

❯❯❯ http -h https://www.example.com
HTTP/1.1 200 OK
age: 0
cache-control: public, max-age=0, must-revalidate
content-encoding: gzip
content-type: text/html; charset=UTF-8
date: Thu, 01 Apr 2021 13:23:30 GMT
etag: "xxx"
server: Netlify
transfer-encoding: chunked
vary: Accept-Encoding
x-nf-request-id: xxx

What does work fine is a splat based definition:

[[redirects]]
  from = "https://www.example.com/*"
  to = "https://example.com/:splat"
  status = 301
  force = true

e.g.

❯❯❯ http -h https://www.example.com/xxx                                                                                       
HTTP/1.1 301 Moved Permanently
Age: 0
Cache-Control: public, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 38
Content-Type: text/plain; charset=utf-8
Date: Thu, 01 Apr 2021 13:58:25 GMT
Location: https://example.com/xxx
Server: Netlify
X-NF-Request-ID: xxx

But obviously this rule does not match for www.example.com or www.example.com/

I did read and work myself through the Redirects Support Guide, but it did not help either. Am I missing something obvious here? Thanks for your help!

Hey! Not too sure on how well we have integrated locale detection in next-on-netlify but what I can say is that our redirects file can’t be used to distinguish between / and not-/ pages. These are normalised as part of the response to the request.

Similarly for www-to-non-www redirects – this is automatically performed prior to any redirect rule, based on what your primary custom domain in the UI is set to!

Hey Pie!

Thanks for the quick response!

But doesn’t that mean that a redirect rule for /* should cover / as well?

Yeah that works well with the default domain. But I have two domains and for the second one I have no way to set it up in the UI, right?

But doesn’t that mean that a redirect rule for /* should cover / as well?

Yes, it should, as long as pretty URLs is ticked in the UI at Netlify (whether Asset Optimization is enabled or disabled is irrelevant).

Yeah that works well with the default domain. But I have two domains and for the second one I have no way to set it up in the UI, right?

Ah, true! This automatic redirect won’t take place for domain aliases and you will need to add rules for http, https, www and bare.

If you’ve got an x-nf-request-id to hand, we can use this to find your account to understand the specifics. We won’t publish any specifics but it’ll help us to understand the site and what you’re trying to achieve.

Also, if you can again very concisely explain something that should work but isn’t, with examples (not including your domain name, if you don’t wish to do this) then that will help us more too.

Pretty urls was not ticked in the UI. I turned it on but it seems to make no difference.

Request id is e.g.: e5cc3a04-8a31-4f66-aa1f-45558b5cabe7-46827891

Domains setup as follows:

  • example.com (Primary domain / default in Next.js / Assigned to english locale)
  • www.example.com (Domain Alias)
  • example.nl (Domain Alias / Next.js Dutch Locale)
  • www.example.nl (Domain Alias)

Scenarios:

  • www.example.com should redirect to example.com :white_check_mark: (works via Netlify UI, no rule defined)
  • www.example.nl/abc should redirect to example.nl/abc :white_check_mark: (redirect rule defined in netlify.toml)
  • www.example.nl should redirect to example.nl :no_entry:
    Rules currently set up include:
[[redirects]]
  from = "https://www.example.nl"
  to = "https://example.nl"
  status = 301
  force = true

[[redirects]]
  from = "http://www.example.nl"
  to = "https://example.nl"
  status = 301
  force = true

[[redirects]]
  from = "https://www.example.nl/"
  to = "https://example.nl"
  status = 301
  force = true

[[redirects]]
  from = "http://www.example.nl/"
  to = "https://example.nl"
  status = 301
  force = true

[[redirects]]
  from = "https://www.example.nl/*"
  to = "https://example.nl/:splat"
  status = 301
  force = true

[[redirects]]
  from = "http://www.example.nl/*"
  to = "https://example.nl/:splat"
  status = 301
  force = true

Ultimately I would like to see two scenarios covered:
a) www redirect to root domain on secondary (non-primary) domain
b) Language based redirect (currently not setup, because I opened this can of worms ;))

For the language based redirect I would redirect:

example.com/ -> example.nl when language = nl
example.nl/ -> example.com when language = en

Important for the language part is that this only happens on / because else folks can’t change language manually anymore.

Hey there,

Quickfire answers to your questions which hopefully give some food for thought this evening!

This guide will help you out with understanding trailing slashes, how to make them perform how you want and the importance of pretty URLs.

As for the slash in the redirect, I don’t think that’s going to be possible. Best workaround would be to consider linking to /index.html or even using query string parameters?

Thanks Pie, unfortunately this means I can’t host the site on Netlify and need to move it over to Vercel.

Hmm, I think we may still be able to get this working if you are still interested in debugging further. After some discussion with our dev team, we think this may be happening since our next.js integration puts its redirects ahead of yours (meaning, yours may never be reached!) as listed in the toml file, specifically. Where we wouldn’t override yours is in _redirects, which would be usable for this use case (your quoted example.com redirects), since those will NOT be overridden by the next.js catch alls.

Hey, thanks for jumping in!

Sure happy to explore it further.

The issue with the _redirects file is that the rules are somehow never picked up (they don’t even show up in the redirect rules count during deploy and of course are also not part of the _redirects file if I download the deploy artifacts). I briefly mentioned that in my initial post.
I followed the debugging steps in the Redirects Support Guide but I couldn’t get it to work so I assumed that somehow the _redirects file is overridden by the nextjs-netlify plugin. I have seen that the plugin does some heavy lifting there.

Shouldn’t be the case: GitHub - netlify/netlify-plugin-nextjs: A build plugin to integrate Next.js seamlessly with Netlify

Netlify redirects should be read ahead of the next.js redirects. The fact they’re not showing in your count makes me think that your redirects file is in the wrong directory. Is it alongside your index.html/netlify.toml file (usually at the root)?