Posted on: 2024/12/18

I was debugging a React app a few weeks back when something caught my eye in the network tab. A simple GET request to my API was actually making two requests: first an OPTIONS request, then the actual GET. My API Gateway logs showed the same pattern: two requests, two charges (you read a $).

That's when it hit me: I was basically paying double for every single request because of CORS preflight requests. Now if you're hosting your API on a subdomain like api.example.com, you might be bleeding money the same way.

What's the problem?

Every time the browser makes a cross-origin request, it first sends a so called preflight request to check if it's allowed to make the actual request. Since API Gateway charges per request, you're getting billed for both, the preflight and the main request.

CORS (Cross-Origin Resource Sharing) is a system, consisting of transmitting HTTP headers, that determines whether browsers block frontend JavaScript code from accessing responses for cross-origin requests.

If you're unsure, a cross-origin request happens when your frontend (e.g example.com tries to talk to a backend that's on a different domain, subdomain, or port (e.g api.example.com. Think of it as your browser's security guard; it wants to make sure the API you're calling is actually expecting requests from your website. It's a crucial security feature, but in our case, it's also causing an unexpected cost overhead.

Here's the thing that surprised me: even if your API is hosted on a subdomain like api.example.com, the browser still treats it as a cross-origin request from example.com. I always thought subdomains would be treated as same-origin. They're not. api.example.com gets treated as if it is a separate origin.

What was (a) solution?

After spotting this in my AWS bill, I moved my API from api.example.com to example.com/api. It basically was just a simple config in my gateway which was straightforward, update the API Gateway custom domain settings, modify my route records, and update the API endpoint in my React app. That's it.

The results were, well, immediate. Not only did my request count drop by almost nearly half (around 40%), but I also noticed a slight improvement in response times. Makes sense, one less network round trip means faster responses for my users.

Now, don't get me wrong. I'm not saying subdomains are bad. They're actually great for keeping your infrastructure organized, especially when you're having multiple services or environments. I've worked with teams that love giving each service its own subdomain. It keeps things clean and gives teams more control over their piece of the system.

But if you're bootstrapping a side project or running a small service where every penny counts, those extra preflight requests can add up. That's when you might want to reconsider your domain strategy.

And hey, if you absolutely need to stick with subdomains, there's a middle ground: Couldflare's CDN or AWS CloudFront. By putting a cache mechanism on top of your gateway, or api, you can handle those preflight requests more efficiently. It won't eliminate the extra costs completely, but it'll definitely be gentler on your wallet. However, this is just a guess and I personally haven't tested it.

So there you have it, a simple domain restructuring that can save you money and speed up your app. It's these small architectural decisions that often make the biggest impact.

If you like my post, I share more of my architectural experiences and cost-saving discoveries on my website. Make sure to subscribe to my newsletter where I break down practical tips and real-world solutions I find in my journey.

Cheers!