Last modified: Oct 14, 2026

How to Install django-cors-headers

Your frontend runs on port 3000. Your Django API runs on port 8000. The browser blocks every request between them with a CORS error.

Cross-Origin Resource Sharing is a browser security feature. It stops web pages from making requests to a different domain unless the server explicitly allows it.

django-cors-headers is the standard package for handling CORS in Django. It adds the right headers to your responses and lets you control which origins are allowed.

This guide walks through the full installation. You will install the package, configure the middleware, set allowed origins, and troubleshoot the errors that trip up most developers.

What Is django-cors-headers?

django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing. It is the most widely used CORS solution in the Django ecosystem.

The package adds response headers that tell browsers which origins can access your API. It also handles preflight OPTIONS requests automatically.

Without it, you would need to write custom middleware and manage headers by hand. django-cors-headers does that work for you with a clean settings-based API.

It works with any Django project, whether you are building a REST API with Django REST Framework or a traditional server-rendered application.

Prerequisites

Before installing django-cors-headers, check that your environment meets these requirements.

  • Python 3.9 or newer installed on your machine
  • Django 4.2 or higher in your project
  • pip available for package installation
  • An active virtual environment is recommended

Activate your virtual environment before installing. This keeps django-cors-headers isolated from other projects on your system.

You should also have a working Django project with at least one API endpoint or view that a different origin needs to access.

Installing django-cors-headers with pip

The installation is a single command. Run this inside your activated virtual environment.

 pip install django-cors-headers 

This downloads the latest stable release from PyPI. The package has no heavy dependencies, so installation is fast.

If you use a requirements file, pin the version for reproducible builds.

 pip install django-cors-headers==4.7.0 

Pinning prevents surprise upgrades during deployment. You can check the current version on PyPI at any time.

You can also use the module form of pip to ensure the package installs for the correct interpreter.

 python -m pip install django-cors-headers 

This is the recommended approach when you have multiple Python installations on your machine.

Verifying the Installation

After installation, confirm the package is importable. Run this command in your terminal.

 python -c "import corsheaders; print('installed')" 

You should see a confirmation message.

 installed 

If you see a "ModuleNotFoundError", pip installed the package for a different interpreter. Use python -m pip install django-cors-headers to target the correct environment.

Adding corsheaders to INSTALLED_APPS

Open your project's settings.py file and add "corsheaders" to the INSTALLED_APPS list.

 # settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Third-party apps 'corsheaders', # Your apps 'myapp', ] 

The app label is corsheaders with no hyphen or underscore. The pip package is django-cors-headers, but the Django app name is just corsheaders.

Without this step, Django will not recognize the CORS middleware and requests will still fail.

Adding the Middleware

The CORS middleware must be placed as high as possible in the MIDDLEWARE list. It should come before any middleware that can generate responses.

 # settings.py MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # Must be first or near the top 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] 

The CorsMiddleware class intercepts requests and adds CORS headers to responses. It also handles preflight OPTIONS requests before they reach your views.

Placement matters because middleware runs from top to bottom. If CORS middleware runs after CommonMiddleware, a response may already be generated without the CORS headers.

If you also use WhiteNoise for static files, the order becomes important. The installation of whitenoise in Django places its middleware after security middleware. CORS middleware should still come first.

Configuring Allowed Origins

By default, django-cors-headers allows no origins. You must explicitly list the domains that can access your API.

Add this setting to your settings.py file.

 # settings.py CORS_ALLOWED_ORIGINS = [ "https://example.com", "https://app.example.com", "http://localhost:3000", "http://127.0.0.1:3000", ] 

Each entry must include the scheme and the domain. Do not add a trailing slash. The origin is the combination of protocol, host, and port.

For development, list both localhost and 127.0.0.1 with the correct port. Browsers treat them as different origins.

In production, always use https. Allowing http origins in production opens a security hole.

Allowing All Origins for Development

During local development, you may want to skip the origin list entirely. The package provides a setting for that.

 # settings.py CORS_ALLOW_ALL_ORIGINS = True 

When this is True, every origin is allowed. The CORS_ALLOWED_ORIGINS list is ignored.

Never use this setting in production. It exposes your API to requests from any website on the internet.

A safer pattern is to switch based on the environment.

 # settings.py import os DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True" if DEBUG: CORS_ALLOW_ALL_ORIGINS = True else: CORS_ALLOWED_ORIGINS = [ "https://example.com", "https://app.example.com", ] 

This gives you convenience in development and tight security in production without changing code.

Allowing Credentials

If your frontend sends cookies or authentication headers, you need to enable credentials support.

 # settings.py CORS_ALLOW_CREDENTIALS = True 

When this is True, the browser is allowed to include cookies and HTTP authentication in cross-origin requests.

There is an important restriction. When credentials are enabled, you cannot use CORS_ALLOW_ALL_ORIGINS = True. Browsers block wildcard origins with credentials for security reasons.

You must list specific origins in CORS_ALLOWED_ORIGINS when credentials are active.

If your project uses authentication packages, this setting often pairs with them. A social login flow that involves a separate frontend domain will need both credential support and a matching origin list. The approach to set up social login with django-allauth covers the authentication side, while CORS handles the browser restrictions.

Customizing Allowed Headers and Methods

By default, django-cors-headers allows a standard set of headers and methods. You can extend that list when your API uses custom values.

 # settings.py from corsheaders.defaults import default_headers CORS_ALLOW_HEADERS = list(default_headers) + [ "x-custom-header", "x-request-id", ] CORS_ALLOW_METHODS = [ "DELETE", "GET", "OPTIONS", "PATCH", "POST", "PUT", ] 

The default_headers list includes common values like accept, authorization, content-type, and x-csrftoken.

If your frontend sends a custom header, it must appear in CORS_ALLOW_HEADERS. Otherwise, the browser rejects the request during the preflight check.

For methods, the default list covers all standard HTTP verbs. You only need to change this if your API uses custom methods.

Using Regex for Dynamic Origins

Some applications serve users from dynamic subdomains. Listing every origin is not practical.

The CORS_ALLOWED_ORIGIN_REGEXES setting accepts regular expressions that match multiple origins.

 # settings.py CORS_ALLOWED_ORIGIN_REGEXES = [ r"^https://\w+\.example\.com$", ] 

This pattern matches any subdomain of example.com over https. It handles cases like app.example.com and staging.example.com.

Regex patterns are powerful but easy to misconfigure. Test them carefully before deploying.

A simpler alternative is the CORS_ALLOWED_ORIGINS list when the number of origins is small and fixed.

How Preflight Requests Work

Browsers send a preflight OPTIONS request before certain cross-origin requests. This checks what the server allows.

django-cors-headers handles these requests automatically. It responds with the allowed methods, headers, and origin.

You can inspect the preflight response with a curl command.

 curl -X OPTIONS http://localhost:8000/api/items/ \ -H "Origin: http://localhost:3000" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: content-type" \ -v 

The response headers show what the server permits.

 Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Methods: DELETE, GET, OPTIONS, PATCH, POST, PUT Access-Control-Allow-Headers: content-type, authorization Access-Control-Max-Age: 86400 

The Access-Control-Max-Age header tells the browser to cache the preflight response for 24 hours. That reduces the number of preflight requests.

If the preflight fails, the actual request never happens. Always check the OPTIONS response first when debugging CORS issues.

Common Installation Problems

Problem: "No module named 'corsheaders'"

The package is not installed for the active Python interpreter. Reinstall with python -m pip install django-cors-headers to target the correct environment.

Problem: CORS headers not appearing in responses

Check the middleware order. CorsMiddleware must be at or near the top of the MIDDLEWARE list. If it runs after other middleware, headers may not be added.

Problem: "Access blocked by CORS policy"

The origin of your frontend is not in CORS_ALLOWED_ORIGINS. Check the exact scheme, host, and port. A missing www or a wrong port causes the mismatch.

Problem: "Credentials flag is true but header is false"

Your frontend sends credentials, but the server does not allow them. Set CORS_ALLOW_CREDENTIALS = True and make sure you are not using wildcard origins.

Problem: Preflight returns 403 Forbidden

The requested method or header is not in the allowed lists. Add the missing value to CORS_ALLOW_METHODS or CORS_ALLOW_HEADERS.

Problem: CORS works in development but fails in production

Production may use a different domain or protocol. Update CORS_ALLOWED_ORIGINS with the production origin and remove any localhost entries.

Problem: Static files still trigger CORS errors

CORS middleware only applies to responses handled by Django. If a separate server or CDN serves your static files, it must add the CORS headers itself.

Best Practices

Never allow all origins in production. Use an explicit list of trusted domains.

Always use https in production. Allowing http origins exposes your users to man-in-the-middle attacks.

Keep the origin list short. Only add domains that actually need access. Every extra origin increases your attack surface.

Use environment variables for configuration. Do not hardcode origins in settings.py. Different environments need different lists.

Test preflight requests manually. A quick curl command reveals whether the server is responding correctly.

Pin the package version. CORS behavior is security-sensitive. A pinned version keeps deployments predictable.

Review the list when adding new frontends. A new subdomain or mobile app origin will need to be added before it can make requests.

If your project also uses filtering or API extensions, those features work independently of CORS. The process of filtering QuerySets with django-filter happens at the database layer and does not affect request headers.

Testing Your CORS Setup

After configuration, test the setup from your browser or a command line tool. Start the development server and send a request with an Origin header.

 curl -I http://localhost:8000/api/items/ \ -H "Origin: http://localhost:3000" 

The response should include the CORS header.

 HTTP/1.1 200 OK Access-Control-Allow-Origin: http://localhost:3000 Content-Type: application/json 

If the header is present, CORS is working. If it is missing, check the middleware order and the allowed origins list.

When you are ready to deploy, review how to deploy a Django app with Fabric to automate the release and ensure your CORS settings carry over to the production environment.

Conclusion

Installing django-cors-headers takes three steps. Run pip install django-cors-headers, add "corsheaders" to INSTALLED_APPS, and add the middleware to your settings.

From there, configure CORS_ALLOWED_ORIGINS with the exact domains that need access. Enable credentials only when your frontend sends cookies. Test preflight requests before deploying.

Most CORS problems come from three sources. The middleware is in the wrong position. The origin list has a typo. Credentials are enabled with wildcard origins.

Fix those three things, and cross-origin requests start working. Your frontend and backend communicate freely, and the browser stops blocking your API calls.