Skew Protection Docs Feedback

I’ve just spent a day or so implementing skew protection for our site (that doesn’t use vercel or astro). And thought I’d send a quick bit of feedback about the documentation/feature.

  1. It might be helpful to document that the .netlify/v1/ folder is kind of weird. As far as I can tell you cannot check it in to the repo, as it will be ignored/overwritten by netlify during the build.

    You also can’t just copy it from say cp _netlify .netlify during the build as the netlify build creates and uses .netlify during it’s own setup.

    So you must explicitly write the files to .netlify/v1 one at a time (and create the directory if it doesn’t exist).

  2. There’s some interesting handling with redirects and skew protection. I think it actually does make sense but it confused me for a while.

    If you have a redirect for say /* => index.html (200) if you try and load (in your browser) something like myscript.SHA.js?deploy_id=past_deploy netlify will return the current index.html instead of the file from the previous build. But if you fetch or curl the same url netlify will return the previous build’s JS file correctly.

    I think this makes some sense, to stop people getting stuck on the old deploy if you are using cookies, but it confused me for a bit.

  3. It would be have been super helpful if anywhere in the UI/logs the build indicated that it had enabled skew protection and with what settings.

  4. There are some caveats that might be worth highlighting, unless there is a way to solve for them I’m unaware of?

    • Cookie based would the best from a caching/simplicity perspective; and we started with that; but realised that since cookies are shared between tabs, it just creates a new skew problem. As if someone has an old version tab open; and then opens the new version, the cookie will get updated; and now the old version tab will be broken again, as it’ll request old version URLS with a new version deploy id
    • Query param is then where you end up, and the only other choice for e.g script/css tags; but the downside is that I believe adding the query param will bust caches. So if a file isn’t changed between deploys it’s cache will now be bust on every deploy.

Hi @dayfunding!

Thank you so much for taking the time to share this feedback with us.

To your points:

It might be helpful to document that the .netlify/v1/ folder is kind of weird. As far as I can tell you cannot check it in to the repo, as it will be ignored/overwritten by netlify during the build.

The .netlify/v1 directory is indeed somewhat special. It’s part of our Frameworks API, and it was designed primarily as a way for web frameworks to provision and configure different parts of the platform. This is a process that frameworks need to do on each build, because the output will be influenced by the source files. For this reason, getting these files checked into version control is not a use case we’ve come across before.

I’d love to understand a bit more about your setup and how you’re implementing this. Do you use any framework at all?

If you have a redirect for say /* => index.html (200) if you try and load (in your browser) something like myscript.SHA.js?deploy_id=past_deploy netlify will return the current index.html instead of the file from the previous build. But if you fetch or curl the same url netlify will return the previous build’s JS file correctly.

You’re spot on. We don’t apply skew protection on browser navigations in order to mitigate the risk of downgrade attacks. But I realise we’re not making this clear in the documentation and we absolutely should.

Let me look into that and get back to you.

It would be have been super helpful if anywhere in the UI/logs the build indicated that it had enabled skew protection and with what settings.

Agree! We’ll add that.

There are some caveats that might be worth highlighting, unless there is a way to solve for them I’m unaware of?

The multi-tab setup is interesting and a challenging one to solve with cookies. As for query parameters, they will bust your browser cache, but our edge cache understands that this query parameter is for skew protection and it’s able to load the file for the old deploy from the cache if it’s there.

And as you point out, query parameters are the right option if you need to load scripts or CSS files.

Thanks again for the thoughtful feedback. I hope you find value in this feature despite any rough edges. I’ll get back to you on the action items I mentioned above.

I’d love to understand a bit more about your setup and how you’re implementing this. Do you use any framework at all?

We just have a (p)react single-page application that we bundle with parcel. We have a number of points where we code split (using async import() calls) our bundle so that we only have to load sections of the app that are needed as they are needed. But this sometimes causes skew issues when we deploy as those lazily loaded bundles from previous deploys are unavailable.

I started implementing this with just cookies: setting a cookie at the very top of index.html with the deploy id. If it wasn’t for my concerns about multiple tabs that would have probably been good-enough.

So I’ve now created a parcel plugin that will as a final step in the build append ?ndi={DEPLOY_ID} to any lazily loaded asset urls. This works, with the downside of busting the (browser) cache.


The irony here is of course that all of our assets are content-addressably hashed in the filename already. It would be even simpler if netlify would just allow us to say: treat all js/css files as being infinitely cacheable and unique based on hashed filenames; and serve any files from the last N days of builds. That would save all this skew protection stuff, for our use case at least.

Thank you for all the feedback. We’ve created necessary action-items and will follow-up once we have any movement on them.