Skip to content

Self-hosting with dynamic URL path parameters

WeWeb apps are Vue.js Single‑Page Applications (SPAs).

When deploying to static hosting providers such as Cloudflare, Netlify, or Vercel, you may notice:

  • ✔️ Navigating to a page with a dynamic path parameter works (e.g., /category → /category/{variable})
  • ❌ Refreshing a page with a dynamic path parameter returns a 404

This is not a bug in your code — it’s a routing configuration issue.

In Simple Terms

Think of your WeWeb app as a hotel where index.html is the Reception Desk.

  1. When you click links inside the app: You are already in the hotel. The receptionist guides you to different rooms (pages) instantly. You don't need to ask the hotel security (the server) for permission.
  2. When you refresh or share a link: You are arriving from outside. You ask the security guard for specific access (e.g. "Room 101").
    • The Problem: In a Single-Page Application (SPA), "Room 101" doesn't technically exist as a separate physical room; it's created virtually by the receptionist. The guard checks his list, doesn't see "Room 101", and says "404 Not Found".
    • The Solution: You give the guard a new instruction: "If someone asks for a room number I don't know, just send them to the Reception Desk (index.html). The receptionist will handle it."

Understanding Your Build Structure

The build you get with your Vue.js application will have an index.html file at the root and other index files for every page. Usually, the root index is called when you start from the home page, but you may need to access a page directly. In that case, the specific index.html file for that page must be served.

Your Build Output Structure

After running npm run build, your dist folder contains:

dist/
├── index.html                          # Homepage (root)
├── assets/                             # JavaScript, CSS, fonts
├── data/                               # JSON data files
├── products/
│   └── index.html                      # Products listing page
└── product/
    └── :param/
        └── details/
            └── index.html              # Product details page template

Each index.html file contains:

  • Specific metadata (title, description, Open Graph tags)
  • The same Vue.js application code (in assets/main-*.js)
  • Different initial page data

The Challenge: URLs with Parameters

Notice the :param folder in the structure above? This is a literal folder name, not a dynamic parameter. It serves as a template for all product pages.

You have:

  • One template file: /product/:param/details/index.html
  • Many possible URLs: /product/1/details, /product/5/details, /product/99/details, etc.

When a user directly visits /product/5/details:

Without proper routing:

  • ❌ Server looks for /product/5/details/index.html → doesn't exist → 404 error
  • ❌ Wrong metadata loaded (or none at all)
  • ❌ Search engines and social media see incorrect information

With proper routing:

  • ✅ Server maps /product/5/details/product/:param/details/index.html
  • ✅ Correct metadata served
  • ✅ Social sharing work perfectly
  • ✅ Vue app loads and renders product #5

Why This Matters

  • Routing reliability: Direct links to dynamic URLs (like /product/5/details) don’t 404; the correct HTML file can be served.
  • User experience: Page refreshes keep users on the right route, and back/forward navigation continues to work.

Solutions For other providers

The solution depends on your provider. To fix this, you need a specific routing rule to ensure the proper index.html is loaded.

Cloudflare

To self‑host your WeWeb app on Cloudflare, we recommend using Cloudflare Pages.

If you deploy a static site without adding a 404.html, Cloudflare Pages may detect you are deploying an SPA and will serve your index.html for paths that don’t match a file. As a result, the exported WeWeb app can work as is, with no manual custom routing needed on your side.

We have documented the step‑by‑step process here:

Pro tip: If you add a 404.html or you want to make SPA fallback explicit, include a _redirects file at the project root:

txt
/*   /index.html   200

This ensures any unknown path is served index.html, letting the Vue router handle it.

Vercel

To properly serve pages with dynamic path parameters when you self‑host your WeWeb app on Vercel, add a vercel.json file at the root of your exported app:

vercel example

The code inside the vercel.json would be something like this:

json
{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

This snippet will work for a straightforward use case. However, for advanced SEO optimization of dynamic routes (serving the :param template instead of root), you may need to add more specific rewrite rules matching your URL patterns.

Docs: https://vercel.com/docs/project-configuration#rewrites

If you also have API routes and want to exclude them from the SPA fallback, put those rules first:

json
{
  "rewrites": [
    { "source": "/api/(.*)", "destination": "/api/$1" },
    { "source": "/(.*)", "destination": "/index.html" }
  ]
}

Netlify

To properly serve pages with dynamic path parameters when you self‑host your WeWeb app on Netlify, add a netlify.toml file at the root of your exported app:

netlify example

The code inside the netlify.toml would be something like this:

toml
[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Docs: https://docs.netlify.com/manage/routing/redirects/overview/

If you also have API routes and want to exclude them from the SPA fallback, add those rules above the fallback:

toml
[[redirects]]
  from = "/api/*"
  to = "/api/:splat"
  status = 200

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Apache

We provide a detailed guide on how to configure Apache to handle dynamic routing and serve the correct template files for SEO purposes.

Nginx

For Nginx, a minimal configuration to handle basic SPA fallback looks like this:

nginx
location / {
  try_files $uri /index.html;
}

Troubleshooting

SymptomFix
Refresh still 404sEnsure rewrite file is at project root, not /public
Static assets breakAdd an exception for /assets/ or generated file paths
API routes get redirectedAdd rules before the SPA fallback
Changes not taking effect?Restart your web server or clear your CDN cache.

Support policy for self‑hosting

  • WeWeb does not provide support for custom self‑hosting setups as part of standard plans.
  • Because hosting environments vary widely (Vercel, Netlify, Cloudflare, NGINX, Apache, etc.), any issues related to hosting configuration, routing rules, or infrastructure must be handled by your hosting provider.
  • We can only guarantee full support when deploying through WeWeb Hosting.
  • For customers on an Enterprise plan, WeWeb can provide guidance and best‑effort assistance for self‑hosting deployments.