Module VI · Part 1 — Going Live with Vue
Vue on Vercel
You built it with Vue. Now the world needs to see it. Deployment is the bridge between your machine and the open web — where your Vue app becomes a living service.
Section 1 — The Great Migration
Why Deployment?
Your localhost is a cocoon. Beautiful, isolated, invisible. Deployment is the metamorphosis — taking your Vue frontend and Express backend from your machine to machines that live on the internet, accessible to anyone, anywhere, 24/7.
Runs on your machine only. Visible to no one but you.
- • Vite dev server on localhost:5173
- • Hot module replacement, instant feedback
- • No SSL, no domain, no internet
- • Perfect for building and testing
Runs on a cloud server. Visible to the whole world.
- • Hosted on Vercel, Render, Netlify, etc.
- • Accessible via a real URL
- • SSL, custom domain, CDN
- • Built for users, not just yourself
The Golden Rule of Deployment
Order matters. Deploy the backend first, capture its URL, then deploy the Vue frontend with that URL as an environment variable. Then go back and update CORS on the backend with the frontend's URL. This dance is normal. You will do it many times.
Section 2 — The Sequence
Order of Operations
Deployment is a three-act play. Each step depends on the one before it. Following the wrong order is the most common source of production bugs.
Push your Express server to Render first. Get a live URL like https://my-api.onrender.com. Keep this URL — you will need it for the Vue frontend.
Push your Vue + Vite app to Vercel. Set VITE_API_URL to your Render URL as an environment variable during deployment.
After Vercel gives you a URL (https://my-vue-app.vercel.app), add it to your Express server's CORS allowlist. Re-deploy the backend.
Open your Vercel URL. Every API call should flow: browser → Vercel (Vue.js) → Render (Express) → data back to the browser.
The Data Flow
Browser ──► Vercel (Vue.js) ──► Render (Express) ──► Data 1. User visits your Vercel URL 2. Vue app loads in the browser 3. Vue app calls VITE_API_URL (your Render URL) 4. Express handles the request and responds 5. Vue renders the data reactively on the page
Section 3 — The Engine Room
Deploy Backend on Render
RENDER Render is a cloud platform that hosts backend services. It connects to your GitHub repository, builds your code, and gives you a public URL. The free tier is perfect for learning — your server will spin down after inactivity and wake up on demand.
Push your Express code to GitHub
Render needs a repository to deploy from. Make sure your Express project has a package.json with a start script.
{
"name": "my-rest-api",
"scripts": {
"start": "node index.js" // ← Render runs this
},
"dependencies": {
"express": "^4.18.0"
}
}Create a Render Web Service
Log in to render.com, click New + → Web Service, and connect your GitHub repo.
Configure Deployment Settings
Set the following in the Render dashboard:
Add CORS middleware (before deploy)
Your Express app needs CORS configured to allow requests from your frontend URL. Install cors and configure it:
const cors = require('cors');
// Allow requests from your Vercel Vue frontend
// Start with a wildcard for testing, then lock it down
const allowedOrigins = [
'http://localhost:5173',
'https://your-vue-app.vercel.app', // ← replace after Vercel deploy
];
app.use(cors({
origin: allowedOrigins,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
}));Deploy and capture the URL
Click Deploy. Render will build and start your server. After a minute, your API will be live at a URL like:
https://my-rest-api.onrender.com
Test it by visiting https://my-rest-api.onrender.com/api/users in your browser.
Section 4 — The Face of the Web
Deploy Vue.js on Vercel
VUE Vercel supports Vue.js out of the box. It detects your Vite-powered Vue project, builds it, and deploys it with automatic SSL and a global CDN. Your Vue app will be live in under a minute.
Create a Vue + Vite project
If you haven't already, scaffold a Vue project with Vite:
npm create vue@latest my-vue-app cd my-vue-app npm install
Select TypeScript, Router, Pinia if you want — or keep it minimal.
Push your Vue app to GitHub
Vercel needs a repository. Push your project to GitHub.
Import the repo on Vercel
Go to vercel.com, click Add New → Project, and import your GitHub repository. Vercel automatically detects Vue.js and sets the build command to npm run build.
Set the Environment Variable
This is the critical step. Add the Render URL as VITE_API_URL in the Vercel dashboard:
The VITE_ prefix tells Vite to expose this variable to the browser at build time.
Use the env variable in your Vue components
In your Vue components, use import.meta.env.VITE_API_URL instead of hardcoding the URL:
// ✅ Correct — uses the env variable
const API_URL = import.meta.env.VITE_API_URL;
const response = await fetch(`${API_URL}/api/users`);
const data = await response.json();
// ❌ Wrong — never hardcode the URL
// const response = await fetch('http://localhost:5173/api/users');Deploy and capture the URL
Click Deploy. Vercel will build your Vue app and give you a URL like:
https://my-vue-app.vercel.app
Section 5 — The Handshake
CORS — Wiring It Together
CORS (Cross-Origin Resource Sharing) is the browser's security mechanism that blocks requests from one domain to another unless explicitly allowed. Your Vercel Vue frontend and Render backend are on different domains — CORS must be configured.
The Problem
When your Vue frontend (on https://my-vue-app.vercel.app) tries to fetch data from your Express backend (on https://my-api.onrender.com), the browser blocks the request because they are different origins. CORS headers tell the browser: “This cross-origin request is allowed.”
The Solution — Update CORS on Express
After Vercel gives you your Vue app URL, go back to your Express code and update the allowed origins:
const cors = require('cors');
const allowedOrigins = [
'http://localhost:5173', // local Vite dev
'https://my-vue-app.vercel.app', // ← your Vercel URL
];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
}));Quick Tip — Using an ENV Variable for Origins
Instead of hardcoding the allowed origins, use an environment variable. On Render, set ALLOWED_ORIGINS to your Vercel URL so you can update it without changing code:
const allowedOrigins = (
process.env.ALLOWED_ORIGINS || 'http://localhost:5173'
).split(',');Section 6 — The Secrets
Environment Variables
Environment variables keep configuration outside your code. The same codebase can run in development, staging, and production — just by changing the values in the environment.
VITE_API_URLSet in: Vercel dashboardUsed in browser (prefix VITE_). Points to your Render API. Accessed via import.meta.env.VITE_API_URL.
ALLOWED_ORIGINSSet in: Render dashboardList of allowed CORS origins. Includes your Vercel URL.
PORTSet in: Render (auto-set)Render sets this automatically. Your Express app should use it.
DATABASE_URLSet in: Render dashboardOptional — connection string to your production database.
Local Development with .env
For local development, create a .env file in your Vue project root:
# .env (Vue project root — NOT committed to git) VITE_API_URL=http://localhost:3000
Vite automatically loads .env files. Add .env to .gitignore to keep secrets out of version control. You can also use .env.local, .env.development, or .env.production for different environments.
Important — VITE_ Prefix Rules
- ✦ Variables with
VITE_prefix are exposed to the browser at build time viaimport.meta.env. - ✦ Variables without the prefix are server-side only in Vite's SSR mode — never exposed to the client.
- ✦ For pure client-side Vue apps (SPA),
VITE_variables are inlined at build time — after changing them, you must rebuild and re-deploy. - ✦ Access them in your Vue components as
import.meta.env.VITE_API_URL— never useprocess.envin Vue.
Section 7 — The Pitfalls
Common Gotchas
Even experienced developers hit these. Read them now, save hours of debugging later.
On Render's free tier, your Express server spins down after 15 minutes of inactivity. The first request after idle time takes 30–60 seconds to wake up. Solutions: upgrade to a paid plan, or set up a cron job to ping your server every 10 minutes.
Use cron-job.org or UptimeRobot to ping https://my-api.onrender.com every 10 min.
Never hardcode http://localhost:3000 in your Vue components. Always use import.meta.env.VITE_API_URL so you can switch between local, staging, and production without editing code.
Use .env for dev, Vercel env vars for production.
If your Vue app can't reach the backend, open the browser console. If you see a CORS error, your backend's allowed origins list doesn't include your frontend URL.
Add the exact Vercel URL to your Express CORS allowlist and re-deploy.
Vue + Vite uses import.meta.env, not process.env. If you try to use process.env.VITE_API_URL in the browser, it will be undefined. Always use import.meta.env for client-side env vars.
Use import.meta.env.VITE_API_URL in all Vue components.
If you use Vue Router in history mode, refreshing a non-root page on Vercel will return a 404. Vercel serves index.html for all routes via a rewrite rule — but you must configure it.
Add vercel.json: { "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] }
Codex Final — Going Live with Vue
The backend lives on Render. The Vue frontend breathes on Vercel. CORS shakes hands across the wire. Environment variables carry your secrets. Your Vue stack is no longer local — it is alive, accessible, real.
Deploy Express first. Capture the URL. This is your API endpoint.
Deploy Vue + Vite with VITE_API_URL pointing to your Render URL.
Update CORS with Vercel URL. Use env vars to keep config fluid.
Next Steps
Now that your Vue app is live, explore: setting up a custom domain, adding SSL certificates (automatic on Vercel), configuring a CI/CD pipeline for automatic deploys on every git push, and adding Vue Router with history mode for multi-page navigation.