Netlify Function with query strings ignores custom Cache-Control header

What has caused the biggest disappointment was the understanding that Netlify works with Remix when I would say is completely false at this point. I get that this really isn’t Netlify’s fault and I don’t believe Netlify has stated specifically that Remix works on Netlify; however our team built a Remix app on Netlify assuming common use case would function correctly.

I hate that we have to move platforms just to use a modern framework. Especially when we see the majority of our apps to be built on Remix for the foreseeable future. From what I understand this works flawlessly on Vercel and our only recourse at this point is to move our entire site and client inventory over there.

Is there a means to work around this for now? I assume not since its baked into the way caching is handled system wide.

1 Like

hi there @doodirock ,

thank you for your patience as we took a breath and got a chance to discuss this internally - of course we don’t want you to have the experience of Remix not working as expected on Netlify, that is definitely very frustrating. And I won’t deny that it really is not working at this point due to some pretty deep seated specificities about our platform that are not simple to change without potentially negative repercussions for many other customers on our service.

What I can say is that we are aware of the problem and of the limitations of remix on Netlify - and we do hope to be able to dedicate resources to make the necessary changes. We can absolutely keep you posted if anything changes/improves here, which i hope it will.

Sorry I don’t have better news in the interim :crying_cat_face:

2 Likes

I’ve just hit this issue too. My use case: I have a function that generates a social image based on query string params.

The image will be identical if the URL is the same. Assuming URLs are the same regardless of query string params breaks this.

Hi, @jakearchibald. This conversation has meandered a bit and I’m not always sure if everyone is comparing apples to apples. So, I want to make sure we are on the same page.

Are you looking to cache with a normal function or an on-demand builder (ODB) function?

For the ODB functions, this is currently a known limitation. Quoting the docs page I linked to above:

  • They don’t provide access to HTTP headers or query parameters from incoming requests.
  • They are protected from repeated invocations by caching generated pages or assets.
  • Response caching is based on the URL path and can’t be customized.

So things like the domain name, the query parameters, and any headers are not currently considered for the caching.

Our support team can make a feature request asking for this to change. If you want us to do so, please reply here to let us know.

You might also mention the requirement query parameters to be included here:

https://github.com/jamstack/jamstack.org/discussions/549

Now, if on the other hand you are asking about caching for normal functions (not ODB functions) - those responses are currently never guaranteed to be cached.

For normal functions, those are not typically cached at all. You can try to cache those responses by having the function return a cache-control header, however, caching isn’t global to the origin (which ODB is) but, instead, it’s specific to the CDN node that returns the function response. The cache eviction from the individual CDN nodes is dependent on numerous factors and your function’s cache-control header can be ignored and expire early (or not be cached at all). The CDN won’t cache longer than the header the says to but it common for it to be cached for less.

For ODB function the caching is global (not CDN node specific) but also has the limitations noted above.

If there are other questions or if we should enter the feature request mentioned, please let us know.

Any progress on correcting the issues with Remix?

Remix uses normal functions, not builders, because it uses the query parameters.

hey @swamidass ! i actually have some good news on this one. We have corrected things with regards to our cache & it is now playing with Remix much better than before!

here is a quick demo:

https://remix-query-cache-demo.netlify.app/?hello=saturn

if you change the query param, (for example to hello=world and hit enter you will see that the page accurately reflects the changes - wheras before, you’d see a stale value as the query params weren’t considered.

if you still have questions, please let us know!

1 Like

This is fantastic news!

2 Likes

yah we think so too! this just got rolled out to the whole CDN, so if anyone sees any problems or inconsistencies, please do let us know.

1 Like

That’s good news. Doesn’t it make builders obsolete now?

Logically, that probably sounds correct, but there are no plans at the moment to deprecate the feature. You can use either of the two.

1 Like

As far “depreciating” the feature, it seems that all the functionality (except the limits) of builders can be accomplished with a redirect.

I suppose I’m curious if there is any more fundamental difference between the two. Perhaps function caching is decentralized, and functions might be recomputed multiple times in different regions, but builders are only computed once per revalidation term?

Hi @swamidass and thanks for the quite reasonable feedback!

I think Builder functions have a slightly different use case - they are automatically cached in a special way that has our results cached across our CDN (anything else you can do to affect caching - setting a cache-control HTTP response header, or setting a custom cache-control header - will affect only an individual browser or a single CDN node’s cache), and in a way you can specifically control cache timeout on (cf On-demand Builders | Netlify Docs).

While yes, if you use only content provided via lambdas or remote servers where you can set a correct cache-control header, you can duplicate the apparent effects of a builder function, it is both harder to configure / easier to misconfigure, rather than being automagic (as builder functions are). One would assume that also the small details about caching (service-wide, versus per-node) don’t matter to you in this case. Given those constraints, you can duplicate builder functions with just our CDN and some config, but it’s not quite a 1:1 replacement as we see it :slight_smile:

1 Like

I see.
Thanks for the clarification.

What about releasing an library that could handle reliably configuring function headers in a way that mirrors builders? I’m sure a lot people would find that useful.

Though I would also agree it isn’t strictly necessary, as if one is careful the functionality can be nearly replicated regardless.

thank you, @swamidass . i’ve passed your idea back to our product team!