Whenever you're building a full stack application, it's common to run two servers: one for the frontend (like your React or Vite app) and one for the backend (like an Express or Flask API). A proxy is a development tool that helps your frontend talk to your backend as if they were part of the same server.
Imagine your frontend is a person trying to send a letter to their backend friend across town. Without a proxy, your frontend has to remember the entire address every time. Not fun! With a proxy, it's like dropping the letter at a nearby post office that already knows where to send it.
In development, hardcoding full backend URLs like http://localhost:5000/api/cats everywhere is a maintenance headache. It works locally, but once you deploy your app, those addresses change. You'll have to update every API call manually. A proxy solves this by letting your frontend use shorter, relative paths like fetch('/api/cats'), and the proxy figures out where to actually send the request.
Think of a proxy like a hotel front desk. You (the guest/frontend) want to order room service (backend API). Instead of calling the kitchen directly (and needing to know its number), you call the front desk and say "Send me dinner." The front desk (proxy) knows where to forward that request.
Let’s say you're building a cat rental app. Your backend API runs on http://localhost:5000 and your frontend runs on http://localhost:5173.
Your backend has a route /api/cats. Your frontend should ideally be able to do:
fetch("/api/cats")
But without a proxy, this sends the request to localhost:5173/api/cats — your frontend port, not backend! This fails because the backend lives on port 5000.
Vite uses a config file located at frontend/vite.config.js. Here’s how you can set up a proxy inside that file:
frontend/vite.config.js
import { defineConfig } from "vite";
export default defineConfig(({ mode }) => ({
server: {
proxy: {
"/api": "http://localhost:5000"
}
}
}));
This means: whenever your app tries to access a route that starts with /api, Vite will forward the request to http://localhost:5000.
/api/catshttp://localhost:5000/api/catsTry this hands-on example:
/api/catsvite.config.js, add the proxy code abovefetch("/api/cats")
.then(res => res.json())
.then(data => console.log(data));
[{ name: "Whiskers" }]import.meta.env in ViteAlways be careful with open proxy setups in production — this tutorial is strictly for development mode. For production, you’ll want to configure a secure reverse proxy or host both frontend and backend under the same domain.
Now go forth and connect those frontend requests to their backend homes with style!