Home

Blog

Blocked by CORS in FastAPI? Here’s How to Fix It

7 min read
Diagram showing a browser blocking a request from a React frontend to a FastAPI backend due to CORS policy
By David Muraya • November 2, 2025

If you've ever tried to connect a React frontend to a FastAPI backend, you've probably seen this error in your browser's console: Access to fetch at 'http://localhost:8000/api/items' from origin 'http://localhost:5173' has been blocked by CORS policy.

This isn't a bug in your code. It's a security feature built into web browsers called Cross-Origin Resource Sharing (CORS). It stops a web page from making requests to a different domain than the one that served the page.

This article explains what CORS is, how it works, and shows you exactly how to configure it in FastAPI so your frontend can communicate with your API without issues.

What is CORS and Why Does It Block My Requests?

CORS is a security mechanism that controls how web pages in one domain can request resources from another. An "origin" is the combination of a protocol (http, https), a domain (localhost, yourapp.com), and a port (:5173, :8000). If any of these three parts differ between your frontend and backend, the browser considers it a "cross-origin" request and blocks it by default for security reasons.

For example, when your React app running on http://localhost:5173 tries to fetch data from your FastAPI backend on http://localhost:8000, the browser sees two different origins and blocks the request.

To fix this, your FastAPI server needs to tell the browser, "It's okay, I trust requests coming from http://localhost:5173." You do this by adding specific CORS headers to your API's responses.

The Solution: FastAPI's `CORSMiddleware`

FastAPI handles this through its CORSMiddleware. It's a middleware that automatically adds the necessary CORS headers to every response from your API.

Here’s how you set it up.

First, import CORSMiddleware and add it to your FastAPI application.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# This is the list of origins that are allowed to make cross-origin requests.
# You can also use a wildcard '*' to allow all origins.
origins = [
    "http://localhost:5173",  # The origin for your React app on your local machine/development environment
    "https://your-production-frontend.com",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/api/items")
def read_items():
    return [{"name": "Item 1"}, {"name": "Item 2"}]

Understanding the `CORSMiddleware` Parameters

Let's break down what each parameter does:

  • allow_origins: This is the most important setting. It is a list of specific origins that are allowed to access your API. You can also use allow_origin_regex to specify a regular expression, like 'https://.*\.yourdomain\.com'.
  • allow_credentials=True: Allows your frontend to include cookies or Authorization headers in its requests. If you set this to True, you cannot use ["*"] for allow_origins, allow_methods, or allow_headers. You must specify them explicitly.
  • allow_methods: A list of allowed HTTP methods. Defaults to ['GET']. Using ["*"] allows all standard methods.
  • allow_headers: A list of allowed HTTP headers. Defaults to []. Using ["*"] allows all headers.
  • expose_headers: By default, the browser can only access a limited set of response headers. If your API includes custom headers (like X-Request-ID) that your frontend needs to read, you must list them here.
  • max_age: The maximum time in seconds that the browser should cache the results of a preflight request. Defaults to 600 (10 minutes).

Middleware Order is Critical

When you use multiple middlewares, their order matters.

CORSMiddleware must be the first middleware you add to your application.

Why? Because it needs to add CORS headers to all outgoing responses, including errors. If another middleware (like an authentication middleware) throws an error before CORSMiddleware runs, the error response won't have the right CORS headers, and the browser will still show a CORS error instead of the actual error message.

I discuss this and other essential middlewares in my guide on 6 Essential FastAPI Middlewares for Production-Ready Apps.

Final Thoughts

Configuring CORS in FastAPI is straightforward once you understand why it is necessary. By adding CORSMiddleware with the correct settings, you can securely allow your frontend application to communicate with your API. Just remember to be specific with your allowed origins, methods, and headers in production, and to always add the CORS middleware first.

For more technical details, you can refer to the official FastAPI CORS documentation or the comprehensive MDN guide on CORS.

For a complete checklist of security best practices for FastAPI, see my FastAPI Security Guide.


FAQ

1. Can I use a wildcard "*" for allow_origins? You can, but it's generally not recommended for production. It allows any website on the internet to make requests to your API. If you also have allow_credentials=True, browsers will reject the configuration as it's insecure. It's best to list your specific frontend domains.

2. My frontend is still getting a CORS error even after adding the middleware. Why? Check these common issues:

  • Middleware Order: Is CORSMiddleware the very first middleware added to your app?
  • Origin Mismatch: Does the origin in the browser's error message exactly match one of the strings in your allow_origins list? Check for typos, different ports, or http vs. https.
  • Server Restart: Did you restart your FastAPI server after making the changes?

3. How do I handle different origins for development and production? A good practice is to load your origins from environment variables. This way, you don't have to change your code when you deploy. I cover this pattern in detail in my guide on centralizing FastAPI configuration with Pydantic Settings.

import os
from pydantic import BaseSettings

class Settings(BaseSettings):
    ALLOWED_ORIGINS: list[str] = ["http://localhost:3000"]

settings = Settings()

app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.ALLOWED_ORIGINS,
    # ... other settings
)

In production, you can set the ALLOWED_ORIGINS environment variable to a comma-separated list like "https://app.example.com,https://www.example.com".

4. What's the difference between this and serving my frontend from FastAPI? This guide is for when your frontend and backend are separate applications running on different origins. You can also configure FastAPI to serve your frontend's static files, which avoids CORS issues entirely because everything is on the same origin. I cover that approach in my guide on Serving a React Frontend with FastAPI.

Share This Article

About the Author

David Muraya is a Solutions Architect specializing in Python, FastAPI, and Cloud Infrastructure. He is passionate about building scalable, production-ready applications and sharing his knowledge with the developer community. You can connect with him on LinkedIn.

Related Blog Posts

Enjoyed this blog post? Check out these related posts!

Serving a React Frontend Application with FastAPI

Serving a React Frontend Application with FastAPI

A Guide to Serving Your Frontend and Backend from a Single Application

Read More...

6 Essential FastAPI Middlewares for Production-Ready Apps

6 Essential FastAPI Middlewares for Production-Ready Apps

A guide to the 6 key middlewares for building secure, performant, and resilient FastAPI applications.

Read More...

How to Protect Your FastAPI OpenAPI/Swagger Docs with Authentication

How to Protect Your FastAPI OpenAPI/Swagger Docs with Authentication

A Guide to Securing Your API Documentation with Authentication

Read More...

A Practical Guide to FastAPI Security

A Practical Guide to FastAPI Security

A Comprehensive Checklist for Production-Ready Security for a FastAPI Application

Read More...

On this page

What is CORS and Why Does It Block My Requests?The Solution: FastAPI's `CORSMiddleware`Understanding the `CORSMiddleware` ParametersMiddleware Order is CriticalFinal ThoughtsFAQ

Back to Blogs

Contact Me

Have a project in mind? Send me an email at hello@davidmuraya.com and let's bring your ideas to life. I am always available for exciting discussions.

© 2025 David Muraya. All rights reserved.