July 18, 2025 · Expo

Proxying Expo Web Requests Through Nginx

Expo Web introduces an interesting challenge, getting around CORS which isn't an issue on mobile devices. Native Expo apps skip CORS entirely, but Expo Web runs in the browser and must respect the proxy stack. However we can use Metro’s (depreciated) enhanceMiddleware hook to forward requests to Nginx (or any reverse proxy) while keeping native builds untouched.

When You Need a Proxy

Local iOS/Android clients can reach https://127.0.0.1 APIs directly, but the web bundle hits the browser CORS wall. Rather than rewriting every fetch call, tunnel the requests through Metro so they inherit the same cookies and headers your proxy provides.

Install Dependencies

Add http-proxy-middleware to your Expo workspace:

yarn add -D http-proxy-middleware

Add enhanceMiddleware

Modify metro.config.js to point the proxy to your local nginx instance.

// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { createProxyMiddleware } = require("http-proxy-middleware");
const connect = require("connect");

const defaultConfig = getDefaultConfig(__dirname);

module.exports = {
  ...defaultConfig,

  server: {
    ...defaultConfig.server,
    enhanceMiddleware(middleware) {
      const app = connect();

      app.use(middleware);

      app.use(
        "/api",
        createProxyMiddleware({
          target: "https://127.0.0.1:8443/api",
          changeOrigin: false,
          secure: false
        })
      );

      app.use(
        "/auth",
        createProxyMiddleware({
          target: "https://127.0.0.1:8443/auth",
          changeOrigin: false,
          secure: false
        })
      );

      return app;
    }
  }
};

Key points:

Testing the Proxy

  1. Start your reverse proxy (Nginx, Traefik, Caddy) on 8443 or any port.
  2. Run npx expo start --web and confirm network requests flow through Metro to the proxy.
  3. Switch back to --ios / --android: native builds ignore enhanceMiddleware and continue hitting upstream services directly.
Because Metro only wraps the web dev server, you don’t need environment-specific fetch logic, native builds stay blissfully unaware of the proxy.