Vue ships as static assets when you build for production

Whether you use Vite + Vue or an older Vue CLI project, production mode emits HTML, JS, and CSS. StaticHost hosts that emission. It does not run vue-cli-service build or vite build for you, and it does not rewrite missing paths to index.html. History-mode vue-router URLs 404 on hard refresh unless you change approach.

Build with Vite + Vue

vite.config.js:

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

export default defineConfig({
  plugins: [vue()],
  base: '/',
  build: { outDir: 'dist' },
})
npm ci
npm run build
cd dist && zip -r ../vue-site.zip .

Env: VITE_* only, baked at build time. See Vite hosting.

Build with Vue CLI

npm ci
npm run build

vue.config.js knobs:

module.exports = {
  publicPath: '/',
  outputDir: 'dist',
}

Wrong publicPath (for example '/repo-name/') breaks assets on a root-hosted StaticHost site.

vue-router and =404

History mode:

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [/* … */],
})

On StaticHost, try_files $uri $uri/ =404 means /users/42 must be a real file or it 404s.

Hash mode (compatible):

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [/* … */],
})

URLs become /#/users/42. The server serves /index.html; Vue reads the hash.

Alternative: SSG/pre-render plugins that write HTML per route so history URLs exist on disk. That is generating files—not requesting a fictional nginx fallback. Companion reading: SPA guide, React counterpart.

Deploy and verify

  1. Upload zip or GitHub artifact branch (no remote npm).
  2. Open HTTPS preview immediately.
  3. Click client navigations, then paste a nested path into the address bar and press enter.
  4. Confirm hash mode survives hard reload; note history mode failure if still enabled.
  5. Roll back from deploy history if needed.
  6. Add custom domain; certificate after DNS verification.

Watch mixed content if any plugin still injects http:// asset URLs.

Pinia/Vuex and API bases

Store libraries are client-side; they do not need server support. Configure API base URLs via import.meta.env.VITE_API_BASE and rebuild per environment. Use Pro staging (3 sites, 10 GB, $30) for a staging bake separate from production.

Plans and boundaries

Starter $9 (1×2 GB), Pro $30 (3×10 GB + staging), Scale $65 (10×30 GB), Business $130 (30×100 GB + teams). Trial ~1 day. No forever-free, cPanel, email, built-in CDN, or PHP/WordPress runtime.

Nuxt note

Nuxt can generate static sites (nuxt generate / static target depending on major version). Only the generated output belongs on StaticHost. A Node-targeted Nuxt server does not. Treat output like any other dist/public tree—host a dist folder.

A realistic week shipping host a vue build online

Monday starts with a broken relative CSS path that only appears once the files leave a designer’s laptop. You flatten the zip so index.html sits at the archive root, redeploy to StaticHost, and HTTPS preview finally matches local intent. Preview HTTPS is available immediately; custom-domain certificates issue only after DNS verifies.

Wednesday adds a custom domain. DNS is created exactly as the dashboard specifies; verification lags an hour; the certificate appears afterward. Someone asks whether email is included—you point them at a mail vendor and keep MX untouched. Deploy history supports rollback when a publish goes wrong.

Thursday an engineer enables history-mode routing for a “cleaner URL.” Refresh on a nested path 404s. You revert to hash routing for the week’s deadline and schedule prerender work properly instead of inventing an nginx rewrite StaticHost will not apply. WordPress/PHP needs a different kind of host.

Friday staging on Pro receives a build with staging API URLs baked via public env prefixes. Production stays on last week’s known-good deploy until Monday’s review. Rollback remains one click if marketing’s late copy drop breaks mobile layout. There is a short trial (~1 day), not a forever-free tier; no cPanel, no email, no built-in CDN product.

StaticHost serves prebuilt files via zip or GitHub and does not run npm, Hugo, or Jekyll remotely.

That week is what host a vue build online looks like when the host stays boring and the team respects file truth.

Worked example: Vue Router history → hash before launch

You are two days from launch. Product wants pretty paths. StaticHost will 404 them on refresh.

// router/index.js — launch-safe
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Account from '../views/Account.vue'

export default createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/account', component: Account },
  ],
})
npm ci
VITE_API_BASE=https://api.staging.example.com npm run build
cd dist && zip -r ../vue-staging.zip .

Deploy to Pro staging ($30/mo includes staging). Hard-refresh /#/account—expect the account view. Hard-refresh /account—expect 404 unless you also prerendered a file. That teaches the team more than a wiki paragraph.

When staging API calls look right, rebuild with production VITE_API_BASE, deploy production, then DNS → verify → certificate. Do not edit minified bundles on the host to flip environments.

Failure table (Vue on StaticHost)

SymptomLikely causeFix
JS under /repo/assets 404base / publicPath leftoverSet base: '/' or publicPath: '/'; rebuild
Refresh on /users/1 404createWebHistory without filesHash history or SSG files
Blank app, console MIME/path errorsNested zipZip dist contents
Staging data in production UIWrong VITE_* at buildRebuild with production env
Pinia state “resets” oddly after deployExpected server sessionKeep state client-side or call your API
Nuxt server routes 500 ideasNode target uploadedOnly upload static generate output

Nuxt reminder: static generate output only—host a dist folder online. No remote npm, no forever-free after ~1 day trial, no email, no cPanel, no built-in CDN, no PHP. Plans: Starter $9 (1×2 GB), Pro $30 (3×10 GB + staging), Scale $65 (10×30 GB), Business $130 (30×100 GB + teams).

Env bake discipline for Pinia-powered screens

Pinia stores often read import.meta.env.VITE_API_BASE once at startup. If production accidentally ships the staging base, every screen looks “fine” while writing to the wrong backend.

Always rebuild—never patch the store in DevTools as a release step. Keep a one-line README reminder: VITE_API_BASE=… npm run build. Use Pro staging to prove the staging bake, then a clean production bake for the live site. Preview HTTPS is enough to catch CORS allowlist mistakes before you touch DNS.

FAQ

Does createWebHistory(import.meta.env.BASE_URL) fix 404s?

It aligns router base with Vite base. It does not add SPA fallback.

Can I use Vite SSR with Vue here?

No. SSR needs a server process.

Why do in-app links work but refresh fails?

In-app links are client-side; refresh asks the server for a file that does not exist. Hash mode or SSG files fix that class of bug.

Should I enable fallback: true in some config?

That is not a StaticHost feature. Ignore advice copied from other hosts’ redirect files.

How do I host VuePress or VitePress docs?

Build the docs site to static files, upload the output directory contents. Same zip discipline applies.