301 Redirects not working with vercel.json

Current VS Expected behavior

Expected Behavior:
When visiting https://acme-old-site.com or https://www.acme-old-site.com, it should perform a permanent (301) redirect to https://acme-new-site.com/products (preserving any subpaths). For example:

  • https://acme-old-site.com/booking should redirect to https://acme-new-site.com/products/booking.

Current Behavior:
The redirect is not occurring as expected. Instead, when accessing https://acme-old-site.com:

  • It currently serves content directly from acme-new-site.com/products but the URL in the browser remains https://acme-old-site.com. There is no 301 redirect detected by httpstatus.io.
  • (Alternatively, if this is what you are seeing): It redirects to https://acme-new-site.com (the base domain) instead of https://acme-new-site.com/products.

vercel.json configuration:

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "redirects": [
    {
      "source": "acme-old-site.com/(.*)",
      "destination": "https://acme-new-site.com/products/$1",
      "permanent": true
    },
    {
      "source": "www.acme-old-site.com/(.*)",
      "destination": "https://acme-new-site.com/products/$1",
      "permanent": true
    }
  ]
}

Project information (URL, framework, environment, project settings)
Project Settings:

  • Root Directory: Configured as packages/ui (in Project Settings > General).
  • Domain Assignment: Both acme-old-site.com and www.acme-old-site.com are “Assigned to Production” in Project Settings > Domains. All UI-based domain redirects for these domains have been explicitly removed.
  • next.config.mjs: The redirects() function has been completely removed from packages/ui/next.config.mjs to avoid any conflicts.
  • DNS: DNS for acme-old-site.com and www.acme-old-site.com is pointing to Vercel’s nameservers (ns1.vercel-dns.com, ns2.vercel-dns.com) and has been confirmed as fully propagated globally via whatsmydns.net.
  • Deployment Status: The latest deployment, containing all the above configurations, has been successfully promoted to production and is marked “Ready”.

Troubleshooting Steps I’ve Already Taken (Extensive):

  1. Performed multiple project redeployments, including “Clear Build Cache” each time.
  2. Aggressively cleared browser cache, cookies, and OS DNS cache on multiple devices and browsers (including incognito mode and different networks).
  3. Verified the exact content and presence of the vercel.json file in the deployed source (via Vercel’s “Source” tab for the active production deployment).
  4. Confirmed that the correct branch (with all fixes) has been promoted to the active production deployment.
  5. Attempted alternative source values in vercel.json (e.g., using has property), but reverted to the standard, correct format after no success.
  6. Tried implementing redirects via next.config.mjs, but encountered build errors because source does not accept domain names, confirming vercel.json is the correct method for this specific cross-domain source redirect.

Given all these exhaustive checks, it appears the redirect rule in vercel.json is not being applied at Vercel’s edge network for acme-old-site.com as expected.

Hi, Andrew! Welcome to the Vercel Community :waving_hand:

Could you try the following configuration? It will use /(.*) as the source pattern instead of including the domain and adds a has condition with type: "host" to specify which domain the redirect applies to.

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "redirects": [
    {
      "source": "/(.*)",
      "destination": "https://acme-new-site.com/products/$1",
      "permanent": true,
      "has": [
        {
          "type": "host",
          "value": "acme-old-site.com"
        }
      ]
    },
    {
      "source": "/(.*)",
      "destination": "https://acme-new-site.com/products/$1",
      "permanent": true,
      "has": [
        {
          "type": "host",
          "value": "www.acme-old-site.com"
        }
      ]
    }
  ]
}

Let us know how you get on!

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.