The Ultimate Guide to Setting Up Your Dev Environment for CORS and Live APIs

You've just started working on a new project, excited to integrate with that shiny API. But when you fire up your local development server and make your first API call, you're hit with that dreaded red error in the console:

Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy

If you're nodding your head in frustration, you're not alone. This is a common pain point that developers face when working with live APIs that have strict CORS policies set up to only allow requests from production domains.

Understanding CORS and Why It Matters

CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers that restricts web applications from making requests to a different domain than the one that served the web page. While this security measure is crucial for protecting users from malicious attacks, it can become a significant hurdle during local development.

The challenge typically manifests in three main ways:

  1. The API only accepts requests from the live domain, making local development impossible

  2. Different browsers handle CORS workarounds inconsistently (what works in Chrome might fail in Safari)

  3. Cookie-related issues arise when using proxy solutions, especially with APIs that use strict cookie scopes

As one developer on Reddit aptly puts it: "Avoiding CORS is a mistake, you will have to deal with it eventually. Develop with a CORS strategy and use certs in your dev environment."

The Anatomy of a CORS Error

Before we dive into solutions, let's understand what's happening when you encounter a CORS error. When your browser makes a request to a different domain, it first sends a "preflight" request using the OPTIONS method. This preflight request asks the server what kinds of requests it accepts.

The server needs to respond with specific headers that indicate:

  • Which origins are allowed to access the resource (Access-Control-Allow-Origin)

  • Which HTTP methods are permitted (Access-Control-Allow-Methods)

  • Which headers can be included in the actual request (Access-Control-Allow-Headers)

  • Whether credentials (cookies, HTTP authentication) can be included (Access-Control-Allow-Credentials)

If any of these headers are missing or don't include your local development environment, you'll encounter the CORS error.

Solution 1: Using Vite's Built-in Proxy

The simplest and most recommended approach for modern development environments is to use Vite's built-in proxy feature. This solution is particularly elegant because it doesn't require any additional packages or complex setup.

Here's how to set it up in your vite.config.js:

export default {
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
}

With this configuration:

  • All requests to /api/* from your application will be proxied to https://api.example.com/*

  • The changeOrigin: true setting is crucial for handling CORS

  • The rewrite function removes the /api prefix before forwarding the request

Now instead of calling https://api.example.com/users, you would call /api/users in your application code. The proxy handles the rest!

Solution 2: Using Local-CORS-Proxy

For cases where you can't modify the development server configuration or need a more flexible solution, local-cors-proxy is an excellent alternative.

Install it globally:

npm install -g local-cors-proxy

Start the proxy by specifying your target API:

lcp --proxyUrl https://api.example.com

This will start a local server (typically on port 8010) that proxies requests to your target API while handling CORS headers. Your requests would now look like:

fetch('http://localhost:8010/proxy/endpoint')
  .then(response => response.json())
  .then(data => console.log(data));

Solution 3: Running a Local API Copy

As suggested by several developers in the community, running a local copy of the API can be the most robust solution, especially for larger teams. This approach has several benefits:

  1. Complete control over the development environment

  2. No CORS issues since everything runs locally

  3. Ability to work offline

  4. Faster response times

You can achieve this using Docker:

# docker-compose.yml
version: '3'
services:
  api:
    image: your-api-image
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development

Solution 4: Browser-Specific Development Tools

Sometimes you need a quick solution for testing or debugging. Modern browsers offer developer tools that can help:

Chrome

  1. Install the CORS Unblock extension

  2. Enable it only when needed for development

Safari

  1. Enable the Develop menu: Preferences → Advanced → "Show Develop menu in menu bar"

  2. Select Develop → Disable Cross-Origin Restrictions

Firefox

  1. Use the CORS Everywhere extension

  2. Toggle it on/off as needed

Important Note: These solutions should NEVER be used in production. They're strictly for development and debugging purposes.

Common Pitfalls and Solutions

When dealing with APIs that use cookies for authentication, you might encounter issues even with proxy solutions. This often happens because cookies have a Domain attribute that restricts where they can be sent.

Solution:

// In your fetch calls
fetch('/api/endpoint', {
  credentials: 'include', // Important for cookies
  headers: {
    'Content-Type': 'application/json'
  }
})

2. Preflight Request Failures

Sometimes the main request works, but the preflight (OPTIONS) request fails. This is often because the server isn't configured to handle OPTIONS requests properly.

Solution in Express.js:

app.options('*', cors()) // Enable preflight for all routes

3. Inconsistent Behavior Across Browsers

As one developer noted: "I added a hosts file to my Mac which kind of works (only in Chrome but not in Safari)". Browser inconsistencies can be frustrating.

Solution:

  • Use standardized proxy solutions like Vite's proxy or local-cors-proxy

  • Avoid browser-specific workarounds in favor of proper CORS configuration

  • Test across multiple browsers during development

Best Practices for CORS in Development

1. Start with Proper Configuration

Don't try to bypass CORS entirely. Instead, set up your development environment properly from the start:

// Example Express.js CORS configuration
const cors = require('cors');
const corsOptions = {
  origin: process.env.NODE_ENV === 'development' 
    ? 'http://localhost:3000'
    : 'https://yourproductionsite.com',
  credentials: true
};
app.use(cors(corsOptions));

2. Use Environment Variables

Keep your CORS configuration flexible using environment variables:

// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: process.env.VITE_API_URL,
        changeOrigin: true
      }
    }
  }
}

3. Document Your Setup

Maintain clear documentation for your team about the CORS configuration:

# Local Development Setup

1. Copy `.env.example` to `.env`
2. Set `VITE_API_URL` to the appropriate API endpoint
3. Run `npm run dev` to start the development server
4. API requests will be automatically proxied through Vite's development server

Testing Your CORS Setup

Remember that tools like Postman won't show CORS errors because they don't enforce the same-origin policy like browsers do. Always test your setup in actual browsers.

Here's a simple test script you can use:

async function testCORSSetup() {
  try {
    const response = await fetch('/api/test', {
      credentials: 'include'
    });
    console.log('CORS is properly configured!');
    return await response.json();
  } catch (error) {
    console.error('CORS configuration issue:', error);
  }
}

Conclusion

CORS issues during development can be frustrating, but they're not insurmountable. By understanding the underlying mechanisms and implementing the right solutions, you can create a smooth development experience while maintaining security.

Remember:

  • Use built-in proxy features when available

  • Consider running local API copies for larger projects

  • Document your CORS setup for team consistency

  • Test across multiple browsers

  • Never disable CORS entirely in production

With these tools and practices in place, you can focus on building your application instead of fighting with CORS errors.

Additional Resources

Raymond Yeh

Raymond Yeh

Published on 04 March 2025

Get engineers' time back from marketing!

Don't let managing a blog on your site get in the way of your core product.

Wisp empowers your marketing team to create and manage content on your website without consuming more engineering hours.

Get started in few lines of codes.

Choosing a CMS
Related Posts
Handling Common CORS Errors in Next.js 15

Handling Common CORS Errors in Next.js 15

Tired of seeing "Access to fetch at... has been blocked by CORS policy" errors? Dive into our guide to master CORS issues in Next.js and streamline your development process.

Read Full Story
Why Your Next.js 15 Cookies Work Locally But Break in Production (And How to Fix It)

Why Your Next.js 15 Cookies Work Locally But Break in Production (And How to Fix It)

Fix Next.js 15 cookie issues in production. Learn proper httpOnly, secure, and sameSite configurations. Debug authentication cookies that work locally but fail in deployment.

Read Full Story
How to Fix 503 Issues on AWS S3 Serving Next.js?

How to Fix 503 Issues on AWS S3 Serving Next.js?

Learn how to resolve 503 errors and LambdaLimitExceeded issues in Next.js applications deployed on AWS S3. Fix blank pages and external redirect problems with CloudFront.

Read Full Story
Loading...