You can deploy Vue.js almost anywhere, but the right answer depends on one question: does your app render on the client only, or does it need a Node.js server? A plain Vue 3 app built with Vite produces static files that any CDN or web server can host for free. A Nuxt app in server rendering mode needs a runtime, which narrows the field to platforms that run Node or containers. Get that split right and the rest of the decision is about price, region coverage and build minutes.
dist folder to Cloudflare Pages, Netlify, Vercel, GitHub Pages or Firebase Hosting, all of which have usable free tiers. For Nuxt with server side rendering, use Vercel, Netlify, Render or a VPS running Node behind Nginx. Whichever you pick, add a history fallback rule that rewrites unmatched paths to /index.html, or every deep link will return 404.Below are eight platforms that work in production, the exact build settings each one expects, and the single configuration line that trips up nearly everyone deploying a Vue router application for the first time.
Static SPA or server rendered: decide this first
Run npm run build on a standard Vite project and you get a dist directory containing index.html, a hashed JavaScript bundle and a CSS file. Nothing in there needs Node at runtime. It is a folder of files, and hosting a folder of files is a solved problem that costs nothing at small scale.
Nuxt is different. In its default universal mode Nuxt builds a Nitro server output under .output and expects a JavaScript runtime to serve requests. You can force Nuxt into full static mode with nuxt generate, which prerenders every route to HTML and gets you back to a static folder, but you lose per request server logic. Vue’s own production deployment guide covers the build side of this in detail.
.output/server directory after building. If it exists, you need a Node runtime. If you only have dist or .output/public, you can deploy to any static host.Eight places to deploy Vue.js in 2026
The table lists the build command and publish directory each platform expects for a stock Vite based Vue project. Prices are published list prices for the entry tier.
| Platform | Build command | Publish directory | SSR support | Entry price |
|---|---|---|---|---|
| Cloudflare Pages | npm run build | dist | Via Workers | Free, 500 builds per month |
| Netlify | npm run build | dist | Yes, via Functions | Free tier, Pro from $20 per month |
| Vercel | npm run build | dist | Yes, first class Nuxt support | Hobby free, Pro $20 per month |
| GitHub Pages | npm run build | dist (via Actions) | No | Free for public repos |
| Firebase Hosting | npm run build | dist | Via Cloud Functions | Free Spark tier |
| Render | npm run build | dist | Yes, as a web service | Static free, services from $7 per month |
| VPS with Nginx | npm run build | /var/www/app | Yes, with PM2 or systemd | $5 to $6 per month |
| Object storage plus CDN | npm run build | Bucket root | No | Pennies at low traffic |
If you are choosing between them purely on convenience, Cloudflare Pages and Netlify are the fastest path from a Git repository to a live URL. The same build and publish settings apply to sibling frameworks, so our walkthroughs on launching Gatsby on Vultr and launching React.js on SiteGround are worth a skim if your team runs more than one JavaScript stack. If your app is Nuxt with server rendering, Vercel is the least friction. If you want total control and predictable cost at scale, a VPS wins, and the setup overlaps almost completely with our guide to installing Node.js on cloud hosting.
The history fallback rule that breaks every first deploy
Vue Router in history mode produces clean URLs like /dashboard/settings. Those paths do not exist as files on disk. Load the home page and click through and everything works, because the router handles navigation in the browser. Refresh the page, or paste the deep link into a new tab, and the server looks for a file at that path, does not find one, and returns 404.
The fix is a rewrite that serves index.html for any path that is not a real file. Every platform spells it differently.
Netlify uses a _redirects file in your public directory, or the equivalent block in netlify.toml:
/* /index.html 200Cloudflare Pages handles SPA routing automatically for most projects, but you can be explicit with a _redirects file using the same syntax. Firebase Hosting uses firebase.json:
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [{ "source": "**", "destination": "/index.html" }]
}
}Nginx on a VPS needs a try_files directive inside the location block:
server {
listen 80;
server_name app.example.com;
root /var/www/app;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|woff2|png|jpg|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}index.html aggressively. Vite fingerprints asset filenames so those can have a one year cache, but the HTML entry point has to be revalidated or users will keep loading a stale bundle reference after every deploy.Deploying to a subdirectory and the base path problem
GitHub Pages serves project sites from https://user.github.io/repo/ rather than the domain root. If you build without telling Vite about that prefix, the generated asset URLs point at /assets/index.js and the browser gets a 404 for every file. Set the base in vite.config.js:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
base: '/repo-name/',
build: { outDir: 'dist', sourcemap: false }
})You also need to tell Vue Router about the same prefix by passing createWebHistory('/repo-name/'). And because GitHub Pages has no rewrite engine, the standard workaround is to copy index.html to 404.html during the build so unmatched paths still load the app shell.
Environment variables and build time secrets
Vite only exposes variables prefixed with VITE_ to client code, and it inlines them at build time. That means two things. First, rename any variable you want in the browser to VITE_API_URL or similar. Second, understand that anything you inline is public. A key baked into a JavaScript bundle is readable by anyone who opens devtools, so genuine secrets belong on a server, not in a static build.
On Netlify, Vercel, Cloudflare Pages and Render you set these in the dashboard under the project’s environment settings, and they apply to the build container. On a VPS, export them in your CI job or in a .env.production file that is generated during the pipeline and never committed. If you are wiring analytics into the app, our notes on tracking a custom event on Google Analytics cover the client side pattern for SPA route changes, which do not fire page views automatically.
Troubleshooting a broken Vue deployment
Blank white page, console shows a 404 for the JavaScript bundle. The base path is wrong. Either you deployed to a subdirectory without setting base, or the publish directory is set to the project root instead of dist.
Home page works, deep links return 404. Missing history fallback. Add the rewrite for your platform as shown above.
Build succeeds locally and fails on the platform. Almost always a Node version mismatch. Pin it with an .nvmrc file or a NODE_VERSION environment variable so the build container matches your machine.
Assets load but the page is unstyled. A reverse proxy is serving CSS with the wrong content type, or a service worker from an earlier deploy is serving cached files. Unregister the service worker and hard reload before you go hunting further.
API calls fail with CORS errors in production only. In development Vite’s proxy hides the cross origin problem. In production the browser talks to the API directly, so the API has to send the right allow origin header, or you have to proxy through the same domain.
dist folder to Git and also build in CI, you will eventually deploy a stale bundle. Pick one source of truth. Building in CI and ignoring dist is the safer default.Frequently asked questions
Can I host a Vue app for free?
Yes, if it is a static SPA. Cloudflare Pages, Netlify, Vercel Hobby, GitHub Pages and Firebase Hosting all have free tiers that cover personal projects and small production sites. Free tiers usually cap builds or bandwidth rather than charging overage, so check the limit before launch.
What folder do I deploy after building a Vue project?
With Vite the default output is dist, produced by npm run build. Vue CLI projects also use dist. Nuxt in static mode writes to .output/public. Point the platform’s publish directory at whichever applies to your setup.
Do I need Node.js on the server to run Vue?
Only for server side rendering. A client rendered SPA is plain HTML, CSS and JavaScript once built, so the server never runs Node. Nuxt in universal mode does need a Node runtime, or a platform that provides an equivalent edge runtime.
Why do my routes 404 after refreshing the page?
Vue Router history mode creates URLs that do not map to files. The server needs a rule that serves index.html for any unmatched path so the router can take over in the browser. Add the fallback for your host and the problem disappears.
Is Vercel or Netlify better for Nuxt?
Both work. Vercel tends to have the smoothest Nuxt server rendering path with less configuration. Netlify is competitive and has a generous free tier. If you are already using one platform for other projects, the tooling consistency is worth more than the marginal difference.
The bottom line
Deploying Vue.js is easy once you separate the static case from the server rendered case. If your build produces a dist folder and nothing else, any CDN backed static host will serve it well for free, and the only configuration you truly need is the history fallback rewrite. If Nuxt is generating a server bundle, pick a platform with a Node runtime or run one yourself on a VPS.
Start on a free tier, connect the Git repository, and set the build command and publish directory correctly on the first try. Move to a paid plan or your own server later, when bandwidth, build concurrency or region control actually become a constraint rather than a hypothetical one.
About this article: GeekBlog covers U.S. technology news, AI, phones, smartwatches and gaming. Every story is written and checked under our Editorial Policy. Spotted a mistake or have a story tip? Contact our editors.

