Deploy a Vue.js Project to Production Without Surprises

deploy Vue.js project

A production deployment is more than uploading files. Your app must build cleanly, load its assets from the right path, protect secrets, and survive a direct visit to any route.

Use this process when you deploy Vue.js project code for a client, a product, or an internal tool. It uses Vue 3 with Vite first, then covers the few changes legacy Vue CLI projects need.

How to deploy Vue.js project code with Vite

A Vite deployment starts with a production build. The build converts your source files into optimized static assets that a host can serve.

Check package.json before you start. A standard Vue 3 Vite project includes a build script such as "build": "vite build".

Build a clean production artifact

Install the project dependencies from the lockfile first. Run:

npm ci

Use npm install only when you are actively changing dependencies or do not have a lockfile. A clean install catches missing packages that a local machine may hide.

Next, create the production files:

npm run build

Vite writes the output to dist/ by default. This is the folder you deploy, not src/, public/, or the full repository. Vite documents the production build process in its build guide.

If the command fails, fix the build before touching hosting settings. Common causes include an invalid import, a missing environment variable, a case mismatch in a file path, or a dependency that only existed on one developer’s machine.

Test the files you will publish

Do not treat a successful build as a successful release. Serve the generated files locally:

npm run preview

Vite normally opens the preview server on http://localhost:4173. Check the homepage, key routes, images, API calls, and browser console.

A local development server can hide production faults. Preview uses the built dist files, so it exposes broken asset paths and missing configuration before customers find them.

Your accepted result is a working production build, not a completed npm run build command.

Set Vite environment variables without exposing secrets

A Vue app runs in the visitor’s browser. Anything included in its JavaScript bundle is visible to that visitor.

Vite exposes only variables that start with VITE_ to client code. Read them with import.meta.env.

A production API base URL can live in .env.production:

VITE_API_BASE_URL=https://api.example.com

Then use it in Vue code:

const apiBaseUrl = import.meta.env.VITE_API_BASE_URL

Keep public settings and private credentials separate

A build-time public setting is safe to send to the browser. An API base URL, public analytics ID, or feature flag may fit this category.

A server-side secret must never use the VITE_ prefix. Examples include:

  • Database passwords, private API keys, payment-provider secrets, and signing keys must stay on a backend, serverless function, or approved secrets store.
  • Browser code can call your backend endpoint, but it must not contain the credential that authorizes the backend.
  • A token restricted to a public domain is still public. Apply provider restrictions, quotas, and monitoring.

Vite replaces import.meta.env.VITE_* values when it builds the application. If you change a value in your hosting dashboard, rebuild and redeploy. A static Vue site cannot retrieve a newly added build variable after the files are already published.

Vite’s environment variable documentation confirms the VITE_ exposure rule and warns against putting sensitive data in client-side variables.

Keep .env.local out of Git when it contains local-only settings. Commit a .env.example file with empty values so other developers know what the app requires.

Configure paths and routes before deployment

A Vue app can work at localhost:5173 and still fail after deployment because the host uses a subdirectory or does not understand client-side routes.

Check both conditions before you publish.

Match Vite’s base path to the live URL

An app hosted at https://example.com/ can use Vite’s default base path, /.

An app hosted at https://example.com/portal/ needs that path baked into its asset URLs. Set the Vite base option in vite.config.ts or vite.config.js:

export default defineConfig({ base: '/portal/' })

The leading and trailing slashes matter. Build again after changing this value.

GitHub Pages project sites are the common example. If the repository is team-dashboard, use base: '/team-dashboard/'. A user or organization site at the root domain can keep /.

Add a history-mode fallback

Vue Router’s createWebHistory() gives you clean URLs such as /settings instead of hash URLs such as /#/settings. It also requires host support.

Use the Vite base path when you create the router:

history: createWebHistory(import.meta.env.BASE_URL)

A visitor who refreshes /settings sends that URL to your server first. If the server looks only for a physical settings file, it returns a 404. The server must return index.html for requests that are not real files. Vue Router explains the requirement in its guide to HTML5 history mode.

For Nginx, the core fallback rule is:

try_files $uri $uri/ /index.html;

Also add a Vue catch-all route. The host fallback loads your app, while the catch-all route gives the user a proper in-app 404 page for unknown paths.

Choose hosting settings that match the build

Most Vue 3 Vite apps are static sites after the build finishes. Netlify, Vercel, Cloudflare Pages, GitHub Pages, Amazon S3 with CloudFront, and a standard Nginx server can host them.

The provider changes the dashboard labels and deployment command. The release logic does not change: install dependencies, run the build, publish dist, and configure route fallback.

Hosting optionBuild commandPublish directoryExtra check
Netlifynpm run builddistAdd a redirect rule for history-mode routes.
Vercelnpm run builddist for a static outputAdd an SPA rewrite when your routes need it.
GitHub Pagesnpm run builddistSet Vite base to the repository path.
Nginx or another servernpm run buildUpload dist contentsAdd the index.html fallback rule.

Vercel can detect Vite projects during import, but check the generated settings before the first production release. Its Vite deployment guide covers build configuration, environment variables, functions, and SPA rewrites.

For Netlify, a _redirects file in public/ can contain this rule:

/* /index.html 200

Vite copies public/ content into the final build output. The rule then publishes with the rest of the site.

Do not upload the dist folder as a nested directory unless the host asks for it. In most cases, the contents of dist become the site’s web root.

Handle API calls, domains, and HTTPS

A Vue deployment can finish without errors while every API request fails. Test the application against the real production API before you mark the release complete.

Confirm the browser can reach your backend

Open browser developer tools and inspect the Network tab. Check that requests use the production API URL, return expected status codes, and do not expose credentials in headers or response bodies.

If your frontend is on app.example.com and your API is on api.example.com, the API must allow the frontend origin through CORS. Configure allowed origins narrowly. Do not use * for authenticated browser requests.

Use HTTPS on the frontend and API. A secure site can block calls to an insecure http:// endpoint as mixed content.

Set the custom domain after the first working release

Publish to the provider’s temporary URL first. It gives you a clean place to verify routing, environment values, and asset paths.

Then connect the production domain, follow the provider’s DNS instructions, and wait for certificate issuance. Run the same checks after the domain changes. Cookie settings, CORS rules, and OAuth redirect URLs often depend on the final domain.

Before you deploy Vue.js project updates, test the full login or payment flow if your app uses one. A homepage check is not enough.

Deploy legacy Vue CLI projects with the right changes

Vue CLI projects still use the same basic release pattern: run a build and publish dist. New Vue 3 applications should use Vite, but you may need to maintain an existing CLI codebase.

The build command is usually:

npm run build

The important differences are configuration names and environment variable prefixes.

Use publicPath, not Vite base

A legacy Vue CLI app deployed below the domain root uses publicPath in vue.config.js:

module.exports = { publicPath: '/team-dashboard/' }

Vite uses base. Vue CLI uses publicPath. Do not copy one setting into the other project’s config file.

Use VUE_APP_, not VITE_

Vue CLI exposes browser variables with the VUE_APP_ prefix. Code reads them through process.env, not import.meta.env.

A legacy production value may look like this:

VUE_APP_API_BASE_URL=https://api.example.com

The same security rule applies. VUE_APP_ variables end up in the browser bundle. They are not a place for secrets. Review the Vue CLI mode and environment variable guide before changing older deployment settings.

Use a release checklist and keep a rollback record

Production problems become expensive when nobody knows what changed. Keep one release record for every deployment.

Record the Git commit, deployment date, person responsible, host URL, environment used, and test result. Store the record in the same project system your team already uses.

Run these checks after each release:

  1. Load the homepage in an incognito browser window and confirm that the expected version is live.
  2. Open a nested route directly, then refresh it to verify the history fallback.
  3. Test the production API, forms, login flow, and one mobile viewport.
  4. Confirm the build contains no private keys, passwords, or private service tokens.
  5. Keep the prior working deployment available until the new release passes checks.

Name the person who can roll back the site. State where the prior artifact or provider deployment is stored. Record the last known good version.

A failed release should have a bounded response. Stop publishing more changes, return to the last trusted deployment, document the error, then fix the source issue in a new build. Do not overwrite the release record and lose the reason the rollback happened.

Final release standard

A reliable Vue deployment has four parts: a tested dist build, correct public configuration, protected server-side secrets, and route fallback that handles direct URLs.

The host can change. The core process does not. Build the app, preview it, publish the correct files, verify the live result, and keep a trusted rollback point for the next release.

Leave a Reply

Your email address will not be published. Required fields are marked *

Verified by MonsterInsights