Fixing SPA 404s and Same‑Origin API Calls with Netlify Redirects and Rewrites
Learn how to use Netlify’s _redirects file and netlify.toml to solve deep‑link 404s in single‑page apps and proxy third‑party APIs, with rule ordering, force overrides, and caching trade‑offs explained.
23 Nov 2025, 08:17 UTC

Problem: 404s on deep links and CORS errors on third‑party APIs
When a React or Vue app is built and deployed to Netlify, the static build contains only index.html and bundled assets. Navigating to /dashboard from a fresh browser or a bookmark triggers a 404 because the server looks for a file named dashboard. Likewise, calling https://api.example.com/data from the browser causes a CORS preflight because the origin is different.
Both issues can be solved with Netlify’s redirect and rewrite system, but the configuration can be confusing. The goal of this post is to show a concrete, tested approach that works for most SPAs and API proxies, while highlighting ordering, force flags, and caching pitfalls.
Redirects vs. Rewrites: What Netlify Actually Does
Netlify distinguishes two kinds of rules:
- Redirect – Sends a 301/302 response to the browser. The browser’s address bar changes to the new URL.
- Rewrite – Keeps the original URL in the address bar, but the requested resource comes from a different path or a proxied endpoint. The response status is usually 200.
For SPA deep‑linking you need a rewrite that serves /index.html for any unknown path. For API proxying you need a rewrite that forwards the request to the external service.
Rule Syntax and Ordering
Both _redirects files (placed in the publish directory) and netlify.toml blocks use the same line‑based syntax:
from to status [force] [headers]
Key points:
/*and/:slugare splats and named placeholders that capture the rest of the URL or a single segment.- The first rule that matches wins. Subsequent rules are ignored for that request.
- When a real file exists that matches
from, the rule is shadowed unless you addforce = true(or a trailing!in_redirects). - In most Netlify projects,
netlify.tomlrules are processed before_redirectsrules. Verify this in the UI if you have both.
Concrete Example: SPA Fallback + API Proxy
Assume a build output folder called dist. Inside dist we place a _redirects file with the following content:
# Serve the SPA for any unknown route
/* /index.html 200
# Proxy API requests to the third‑party service
/api/* https://api.example.com/:splat 200 force
Explanation:
- The first rule rewrites all unknown paths to
/index.htmlwith a 200 status, enabling client‑side routing. - The second rule proxies any path under
/api/to the external API, preserving the path after/api/via the:splatplaceholder. Theforceflag ensures this rule runs even if a file namedapiexists in the build.
In netlify.toml you could write the same rules inside a [[redirects]] block, which is often cleaner for larger projects:
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[redirects]]
from = "/api/*"
to = "https://api.example.com/:splat"
status = 200
force = true
Testing the Rules Locally
Before deploying, run:
netlify dev
Then in another terminal, use curl to check the behavior:
curl -I http://localhost:8888/dashboard
# Expect:
# HTTP/1.1 200 OK
# Content-Type: text/html; charset=UTF-8
curl -I http://localhost:8888/api/users
# Expect:
# HTTP/1.1 200 OK
# (headers from the third‑party API)
Deploy a preview to confirm the same rules work in the real environment before promoting to production.
Trade‑offs and Limitations
- Permanent Redirects (301) are cached aggressively. If you accidentally set a 301 for a route that should be a rewrite, users will see the old URL until the cache expires. While you can use
302during development, stick to200for SPA fallbacks and API proxies. - Proxy Limits – Netlify’s edge proxy inherits the same timeout and payload limits as serverless functions (currently 10 s and ~10 MB). Long‑running or streaming APIs may fail.
- Rule Count – Free plans allow up to 100 rules. If your project needs more, consider consolidating or moving to a paid plan.
- Query Strings – By default, Netlify ignores query strings when matching rules. If you need query‑specific behavior, use the advanced
querysyntax, but test thoroughly. - File System Clean‑ups – Some build tools delete the
_redirectsfile during the final copy step. Ensure your build pipeline preserves it.
Practical Checklist Before Going Live
- Place
_redirectsornetlify.tomlin the publish directory. - Run
netlify devand test all target URLs withcurl -I. - Create a Deploy Preview and verify the same URLs resolve correctly.
- Check the Netlify UI’s Redirects panel to confirm the rules were parsed.
- Deploy to production and monitor the
404logs for any missed routes.
By following this workflow, you can reliably solve SPA deep‑link 404s and CORS‑blocked API calls without touching your client code.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.