OxyPages

The Vite Base Path: Fix Blank Pages And Broken Assets

The Vite Base Path: Fix Blank Pages And Broken Assets

A blank page after deploy usually means the Vite base path is wrong. What base does, when to set it, why './' breaks routers, and the two places it can't reach.

The OxyPages Team · · 8 min read

You deployed your Vite app, opened the link, and got a white page. No error on screen, no content, nothing. Open the browser console and it's full of red: GET https://you.github.io/assets/index-DSXtc1GT.js 404.

That address is the clue. Your app lives at /my-repo/, but the page is asking for its JavaScript at the root of the domain, where nothing exists. The setting that controls this is the Vite base path, and it defaults to /.

At the root of a domain, / is correct and you never think about it. Move the app into a subfolder, which is exactly what a GitHub Pages project site does, and every asset request points one level too high.

The fix is one line in vite.config.js. But there are three ways to write that line, and one of them quietly breaks apps that use a router. If the app isn't online yet, deploying a Vite app from its dist folder comes first. Below is what each value does, which one to pick, and the two places where setting it isn't enough: the router, and any asset path you typed by hand.

TL;DR: Vite's base option sets the path every built asset is requested from. It defaults to /, which is right when your app sits at the root of a domain or subdomain. For a subfolder, like a GitHub Pages project site, set base: '/my-repo/' with both slashes and rebuild. base: './' makes paths relative, which suits an embedded app but breaks nested routes in a history-router app. Also pass the base to your router, and import assets instead of typing /logo.png, because hand-typed paths are never rewritten.

What Is The Vite Base Path?

The Vite base path is the public URL prefix your app is served from. Vite writes it into every asset URL during npm run build, so the browser knows where to fetch the JavaScript, CSS and images. It's the base option in vite.config.js, and Vite's documentation of the base option lists its default as /.

I built the same app three times on Vite 8.3.6 to show exactly what changes, and a rerun on Vite 8.3.8 on 13 November 2026 gave identical output. Here's the script and stylesheet tag from dist/index.html each time:

base valueWhat index.html asks forWorks when the app is at
'/' (default)/assets/index-DSXtc1GT.jsThe root of a domain or subdomain
'/demo/'/demo/assets/index-CPcTYj_z.jsexample.com/demo/ only
'./'./assets/index-ql14x63E.jsAnywhere, relative to the page

With the default, the request starts at the domain root. With /demo/, every request is prefixed. With ./, each path is relative to whatever page loaded it, which sounds like the safe choice and mostly is, with one exception covered below.

When Do You Need To Set It?

You need it whenever the app isn't served from the root of its domain. That covers four common setups:

  • A GitHub Pages project site. It lives at username.github.io/repo-name/, so base must be '/repo-name/'. A user site at username.github.io sits at the root and needs nothing.
  • A subfolder on an existing website. Your app at example.com/tools/calculator/ needs base: '/tools/calculator/'.
  • An app embedded in another page or platform, where you don't know the final path in advance. That's the case Vite's docs give for a relative base.
  • A reverse proxy that mounts the app under a path like /dashboard/.

And you never need it on a host that gives each project its own subdomain. Netlify's *.netlify.app, Cloudflare's *.pages.dev, Vercel's *.vercel.app and OxyPages' *.myoxypages.com all serve your app at /, and so does a custom domain pointed at any of them. If you're on one of those and seeing a blank page, the base path probably isn't your problem.

That's also my main advice if you can choose: put the app on its own subdomain and leave base alone. It's one less setting to keep in sync, and the GitHub Pages subfolder setup is where this bug shows up most. The trade-offs of GitHub Pages are worth reading if that's where you are.

How To Set The Base Path In Vite

Set it in vite.config.js and rebuild:

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [react()],
  base: '/my-repo/',
})

Or pass it on the command line for a single build, which is handy in a deploy script: vite build --base=/my-repo/.

Whichever you use, your code can read the value back as import.meta.env.BASE_URL, one of Vite's built-in env variables. Vite's guide to env variables and modes lists it, and the guide to Vite environment variables explains how those values get baked into the build.

Three rules keep it working:

  1. Start and end with a slash. '/my-repo/', not 'my-repo' or '/my-repo'.
  2. Match the real path exactly. URL paths on most hosts are case sensitive, so /My-Repo/ and /my-repo/ aren't the same folder.
  3. Rebuild after changing it. The base is baked in at build time. Changing the config without running npm run build changes nothing on the live site.

Before uploading, check dist/index.html. If the script tag says /my-repo/assets/..., the base took effect.

Relative Base: When './' Breaks Your App

Relative Base: When './' Breaks Your App - OxyPages

A relative base like './' makes every asset URL relative to the page that loaded it. Vite's docs suggest it when you don't know the deploy path in advance, and for a one-screen app it works anywhere.

The trouble starts with a history router and nested routes. Say someone opens example.com/app/settings/profile directly, and the host's fallback serves index.html. The browser resolves ./assets/index.js against the current URL and requests /app/settings/assets/index.js.

That file doesn't exist. Depending on the host you get a 404, or, worse, your index.html served in place of the script, which shows up as Unexpected token '<' in the console.

So my rule of thumb:

  • One screen, or a hash router: './' is fine.
  • A history router with nested routes: use the absolute path, '/my-repo/'.

The single-page fallback itself is a separate fix, and the 404 on refresh guide has it for each host.

Two Places The Base Path Doesn't Reach

Two Places The Base Path Doesn't Reach - OxyPages

Setting base fixes what Vite can see. Two things it can't.

Your Router Needs It Too

Vite rewrites asset URLs, but it doesn't tell your router where the app lives. Without that, React Router sees the path /my-repo/settings, looks for a route called /my-repo/settings, and renders nothing.

React Router takes a basename, and Vue Router takes the base as the argument to createWebHistory. Vite exposes your configured value as import.meta.env.BASE_URL, so you only set it in one place:

// React Router
<BrowserRouter basename={import.meta.env.BASE_URL}>
  <App />
</BrowserRouter>

// Vue Router
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
})

The Vue line is what create-vue scaffolds by default, which is why Vue apps hit this less often than React ones.

Paths You Typed By Hand Aren't Rewritten

Vite adjusts asset URLs it knows about: files you import in JavaScript, url() in CSS, and references in index.html. A path written as a plain string in your code is just text, and Vite leaves it alone.

My test build showed this with create-vite's own React template. The hero image is imported, so with base: '/demo/' it became /demo/assets/hero-CLDdwZDr.png. The social icons use a hand-typed href="/icons.svg#github-icon", and after the build they still pointed at /icons.svg. Under a subfolder, those icons break while the rest of the page works.

Two fixes:

  1. Import the file from src/assets so Vite tracks it and rewrites the URL.
  2. Prefix the path at runtime for files in public: build the URL from import.meta.env.BASE_URL plus 'icons.svg'. Vite's docs note the variable is replaced at build time, so it has to appear exactly as written.

Walkthrough: A Vite App On A GitHub Pages Project Site

Here's the sequence I'd follow for a React app in a repository called budget-tracker:

  1. Set base: '/budget-tracker/' in vite.config.js.
  2. Pass import.meta.env.BASE_URL to BrowserRouter as its basename.
  3. Search the code for src="/ and href="/ and either import those files or prefix them with the base.
  4. Run npm run build and open dist/index.html. The script tag should start with /budget-tracker/assets/.
  5. Run npm run preview and visit http://localhost:4173/budget-tracker/. Vite's preview server serves the build under the base, so this is a real test.
  6. Publish dist to Pages and open username.github.io/budget-tracker/. Click through, then refresh on a deep route.

If step 6 shows the page but refresh on a route 404s, the base is fine and you need the fallback. If you'd rather not deal with subfolders at all, a host that gives the app its own subdomain skips this whole post.

What To Do Next

Open the console on your blank page and read the failing URL. If it's missing your subfolder, set base to that subfolder with slashes at both ends, pass it to your router, rebuild and redeploy.

If you can put the app on its own subdomain instead, do that and delete the setting. Publish your build at its own address on OxyPages, where every project gets a subdomain served from /. For a portfolio or a personal project, start a free account, no card needed. It hosts the built files only, so if your app needs a server, pick a host that runs one.

FAQ

Why Is My Vite App A Blank Page After Deploying?

Usually because the Vite base path doesn't match where the app is served. Open the console: 404s for files under /assets/ mean the build asked for assets at the domain root while the app sits in a subfolder. Set base to that subfolder and rebuild.

Should I Use base './' Or An Absolute Path?

Use an absolute path like '/my-repo/' if your app uses a history router with nested routes, because a relative base resolves assets against the current URL and breaks on deep links. Use './' for a single-screen app or one you embed somewhere with an unknown path.

Does The Base Path Affect Files In The Public Folder?

Vite rewrites references to them in index.html and CSS, but not paths typed as strings in your JavaScript or JSX. Prefix those with import.meta.env.BASE_URL, or move the file into src/assets and import it.

Do I Need A Base Path On A Custom Domain?

No, as long as the app sits at the root of that domain. A custom domain pointed at a GitHub Pages project site serves from /, so you'd set the Vite base path back to '/' when you add the domain.

Try It Now

Still Here? Drop It In.

The whole pitch fits in one sentence: your HTML, on a link, in seconds.

Drag and drop your HTML files, a folder, a ZIP, your app's build folder, a PDF or an image

or ·

No account needed. Your unclaimed website stays live for 30 minutes on a free subdomain. Claim it to your account to keep it permanently.

  • No Account Needed
  • Free SSL
  • 30-Minute Unclaimed Link, Claim To Keep It