The error you’ll definitely see
The first time your React frontend tries to call your FastAPI backend, you’ll see this in the browser console:What is CORS?
CORS (Cross-Origin Resource Sharing) is a browser security feature. It prevents a website from making requests to a different domain/port unless that server explicitly allows it. An origin is a combination of protocol + domain + port:| URL | Origin |
|---|---|
http://localhost:5173 | http://localhost:5173 |
http://localhost:8000 | http://localhost:8000 |
https://myapp.com | https://myapp.com |
https://api.myapp.com | https://api.myapp.com |
localhost:5173) and your FastAPI backend (localhost:8000) have different origins because they’re on different ports. The browser blocks the request by default.
CORS is a browser-only security feature. It doesn’t affect Postman, curl, or server-to-server requests. That’s why your API works fine in FastAPI’s Swagger UI (
/docs) or when you test with curl, but breaks when called from React.The companion repo allows more than one dev origin because the same API is used by multiple clients:
http://localhost:5173 (Vite web frontend) and http://localhost:8081 (Expo web while testing the mobile app).Why CORS exists
Without CORS, any website could make requests to any other site using your credentials. Imagine visiting a malicious site that silently makes requests to your bank’s API using cookies your browser already has stored. CORS prevents this by requiring servers to opt in to receiving requests from other origins.The fix: FastAPI CORS middleware
Tell FastAPI to accept requests from your React frontend:What each option does
| Option | Value | Meaning |
|---|---|---|
allow_origins | ["http://localhost:5173"] | Which frontends can make requests |
allow_credentials | True | Allow cookies and auth headers |
allow_methods | ["*"] | Allow GET, POST, PUT, DELETE, etc. |
allow_headers | ["*"] | Allow Content-Type, Authorization, etc. |
Development vs production origins
In development, your frontend runs atlocalhost:5173. In production, it runs at your actual domain. Handle both:
How CORS actually works
When your browser makes a cross-origin request, it adds anOrigin header:
Access-Control-Allow-Origin header:
Debugging CORS errors
If you still see CORS errors after adding the middleware:Check the origin matches exactly
http://localhost:5173 is not the same as http://localhost:5173/ (trailing slash) or http://127.0.0.1:5173 (IP vs hostname).Make sure middleware is added before routes
The CORS middleware must be added before your route definitions. FastAPI processes middleware in order.
Check the Network tab
Open DevTools → Network tab. Look at the failing request. Check the Response Headers for
Access-Control-Allow-Origin. If it’s missing, the middleware isn’t configured correctly.What’s next?
Your frontend can talk to your backend. But right now,fetch() calls are scattered throughout your components. Let’s organize them into a dedicated API client layer.
API client layer
Separate API calls from components for cleaner, more maintainable code