Zum Inhalt springen

How we saved $300 using GraphQL, Apollo and Nginx

Last month, our Contentful usage exploded to over 5 million requests… and we hadn’t even launched yet.

Hi guys, I know I’m not the most consistent poster, but I want share with you how we debugged this mystery, saved hundreds of dollars, and I learned to love GraphQL along the way.

„GraphQL“ — have you ever heard of it?

I’d been hearing about GraphQL for quite some time. I’d read about its potential benefits, but I could never find a solid reason to replace my regular REST APIs with it… until a few weeks ago.

If you’re interested, you can check out more about what GraphQL actually is with this amazon article: GraphQL vs REST

Quick context

I’m currently working as a Software Engineer at Observatório da Caatinga e Desertificação, where we’re building an open data platform to raise awareness about socio-economic and environmental indexes about Brazil’s Northeast region. The project is funded by this governmental regional development agency called Sudene.

After some discussion, we decided to use Contentful as our Headless CMS instead of hosting our own or creating an API that connects to our own database. The reasons for that choice aren’t important right now, but feel free to reach out if you want to chat about it. <3

Contentful’s usage

Contentful’s free tier allows up to 100k requests per month. “Great,” we thought. “Plenty.”

Turns out… not so much.

After hitting that limit for a couple of months in a row, our bill would jump $300. Not a massive number, but every penny counts haha.

Then one day, we got a warning: we had already blown past our free tier limit for the month. And this was before launch!

Five million requests?!

Yep. Five. Million. Requests. In a single month.

“What happened?? We haven’t even released the platform yet!” That was everyone’s reaction.

We started debugging. Then after a while, we finally got a solid lead.

The causes

First, we noticed two health check monitors (Route53 and Blackbox) pinging our beta and main apps every 30 seconds from six regions worldwide. The problem? They were hitting the home page, which triggered content fetching.

Fixing that was easy: we added a /health route that returns a simple response.

That explained some of the extra requests… but not the million. We still had half the puzzle to solve.

The second cause? Our own code (of course haha).

Contentful’s regular client can’t query multiple entity types in a single request, meaning we had to fetch them one by one. And you know what that means, right? Yep — some of our pages had a LOT of different entities, in some cases we had almost ten requests per page.

Now, let’s do the math:


// we added a 1-minute revalidate in so it only fetched Contentful once per minute
minutes_per_day = 1440 

// because we checked the home page:
health_check_queries = 8 

regions = 6
days_per_month = 30
monitors = 2

requests_per_month = 1440 * 8 * 6 * 30 * 2 # -> almost 5 Million

The math was mathing.

Now, how to fix it?

Holy GraphQL

This is when I finally got why people love GraphQL.

With the regular client, I had to make separate requests because I couldn’t control how the external API worked. Making weird fix to request everything wasn’t an option — and even if it was, it wouldn’t have felt very elegant with the resources I had.

With GraphQL, I could ask for exactly the entities and attributes I needed, all in one query (within Contentful’s complexity limit).
That took our requests per page from 8–10 down to an average of 2.

But even with GraphQL in place, those misconfigured monitors hinted at another future problem: success.

The holy trinity

If the platform does well (fingers crossed 🤞), more traffic means more requests. And if every time a user visits Data Nordeste we hit the API — even with GraphQL — we’d run into the same problem eventually.

The fix we got? Caching.

We used nginx to cache the HTML rendered by Next.js on the server, and Apollo’s GraphQL caching on the client side.

The outcome: from 6 million requests in July to 24,000 these next months (estimated).

Now, what did we learn today?

I know this might seem trivial to some of you with more experience, but I love this kind of challenge. Having a problem that NEEDS to be solved and engineering a solution is exactly why I love this career so much.

I really enjoyed learning more about GraphQL and caching. Next, I want to build a backend using GraphQL to see how it really works — maybe I’ll write another post about that soon.

Thanks to my team at OCA — working with you guys is amazing. ❤️

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert