Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Ok, I'm almost giving up on this, but how can I disable the caching from Nginx for JavaScript files? I'm using a docker container with Nginx. When I now change something in the JavaScript file, I need multiple reloads until the new file is there.

How do I know it's Nginx and not the browser/docker?

Browser: I used curl on the command line to simulate the request and had the same issues. Also, I'm using a CacheKiller plugin and have cache disabled in Chrome Dev Tools.

Docker: When I connect to the container's bash, and use cat after changing the file, I get the correct result immediately.

I changed my nginx.conf for the sites-enabled to this (which I found in another stackoverflow thread)

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|xml|html|htm)$ {
    # clear all access_log directives for the current level
    access_log off;
    add_header Cache-Control no-cache;
    # set the Expires header to 31 December 2037 23:59:59 GMT, and the Cache-Control max-age to 10 years
    expires 1s;

However, after rebuilding the containers (and making sure it's in the container with cat), it still didn't work. This here is the complete .conf

server {
    server_name app;
    root /var/www/app/web;
    # Redirect to blog
    location ~* ^/blog {
        proxy_set_header Accept-Encoding "";
        sub_filter 'https://testproject.wordpress.com/' '/blog/';
        sub_filter_once off;
        rewrite ^/blog/(.*) /$1 break;
        rewrite ^/blog / break;
        proxy_pass     https://testproject.wordpress.com;
    # Serve index.html only for exact root URL
    location / {
        try_files $uri /app_dev.php$is_args$args;
    location ~ ^/(app|app_dev|config)\.php(/|$) {
        fastcgi_pass php-upstream;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
        # Prevents URIs that include the front controller. This will 404:
        # http://domain.tld/app_dev.php/some-path
        # Remove the internal directive to allow URIs like this
        internal;
    location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|xml|html|htm)$ {
        # clear all access_log directives for the current level
        access_log off;
        add_header Cache-Control no-cache;
        # set the Expires header to 31 December 2037 23:59:59 GMT, and the Cache-Control max-age to 10 years
        expires 1s;
    error_log /var/log/nginx/app_error.log;
    access_log /var/log/nginx/app_access.log;

I have the following nginx virtual host (static content) for local development work to disable all browser caching:

server {
    listen 8080;
    server_name localhost;
    location / {
        root /your/site/public;
        index index.html;
        # kill cache
        add_header Last-Modified $date_gmt;
        add_header Cache-Control 'no-store, no-cache';
        if_modified_since off;
        expires off;
        etag off;

No cache headers sent:

$ curl -I http://localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Mon, 24 Jul 2017 16:19:30 GMT
Content-Type: text/html
Content-Length: 2076
Connection: keep-alive
Last-Modified: Monday, 24-Jul-2017 16:19:30 GMT
Cache-Control: no-store
Accept-Ranges: bytes

Last-Modified is always current time.

Note: nginx's $date_gmt format is not per the HTTP spec (see changing the format).

To disable caching for a particular file extension (e.g. JS as requested by the OP):

location ~* \.js$ {
    expires -1;

See Nitai's answer below to expand the list of file extensions - using a non-capturing group regex pattern.

You only need no-store. From MDN: Although other directives [besides no-store] may be set, this alone is the only directive you need in preventing cached responses on modern browsers. max-age=0 is already implied. Setting must-revalidate does not make sense because in order to go through revalidation you need the response to be stored in a cache, which no-store prevents – felixbade May 21, 2020 at 9:55 @Greg K In the response, the Last-Modified: Monday, 24-Jul-2017 16:19:30 GMT is the wrong format and it can still return cache files as it does not consider Last-Modified as an invalid format. – H_H Jan 30, 2021 at 7:06 @hareshhanat thanks, tell that to my bash terminal (at the time). As this isn't part of the solution (just example output) hopefully it's not causing a problem. – Greg K Jan 31, 2021 at 19:26 @GregK It creates the issue and still, cache the static files as Last-Modified date format is wrong. – H_H Feb 1, 2021 at 9:54

The expires and add_header directives have no impact on NGINX caching the files, those are purely about what the browser sees.

What you likely want instead is:

location stuffyoudontwanttocache {
    # don't cache it
    proxy_no_cache 1;
    # even if cached, don't try to use it
    proxy_cache_bypass 1; 

Though usually .js etc is the thing you would cache, so perhaps you should just disable caching entirely?

It's okay for me to cache it in production, just not in development. I'll try your suggestion – Musterknabe Oct 25, 2016 at 15:36 I did, that's why I asked him if he means proxy_no_cache instead of proxy_no_store. I set it to sth. else than 0 (1), and it didn't work either. – Musterknabe Oct 26, 2016 at 6:35

What you are looking for is a simple directive like:

location ~* \.(?:manifest|appcache|html?|xml|json)$ {
    expires -1;

The above will not cache the extensions within the (). You can configure different directives for different file types.

This answer address the part of the OP's question specific "for JavaScript files" better than the accepted answer. Although the OP may have been happy with the accepted answer, those who come here because of the "for JavaScript files" part of the question will find @Nitai's to be more relevant. Upvoting. – Bryton Beesley Feb 9 at 22:11 index index.php index.html index.htm; try_files $uri $uri/ =404; #.s. el /index.html para html5Mode de angular #.s. kill cache. use in dev sendfile off; add_header Last-Modified $date_gmt; add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; etag off; proxy_no_cache 1; proxy_cache_bypass 1;

I have the following Nginx virtual host(static content) for local development work to disable all browser caching:

    upstream testCom
         server localhost:1338;
    server
            listen 80;
            server_name <your ip or domain>;
            location / {
            # proxy_cache   datacache;
            proxy_cache_key $scheme$host$request_method$request_uri;
            proxy_cache_valid       200     60m;
            proxy_cache_min_uses    1;
            proxy_cache_use_stale   updating;
            proxy_pass_header Server;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Scheme $scheme;
            proxy_ignore_headers    Set-Cookie;
            userid          on;
            userid_name     __uid;
            userid_domain   <your ip or domain>;
            userid_path     /;
            userid_expires  max;
            userid_p3p      'policyref="/w3c/p3p.xml", CP="CUR ADM OUR NOR STA NID"';
            add_header Last-Modified $date_gmt;
            add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
            if_modified_since off;
            expires off;
            etag off;
            proxy_pass http://testCom;

I know this question is a bit old but i would suggest to use some cachebraking hash in the url of the javascript. This works perfectly in production as well as during development because you can have both infinite cache times and intant updates when changes occur.

Lets assume you have a javascript file /js/script.min.js, but in the referencing html/php file you do not use the actual path but:

<script src="/js/script.<?php echo md5(filemtime('/js/script.min.js')); ?>.min.js"></script>

So everytime the file is changed, the browser gets a different url, which in turn means it cannot be cached, be it locally or on any proxy inbetween.

To make this work you need nginx to rewrite any request to /js/script.[0-9a-f]{32}.min.js to the original filename. In my case i use the following directive (for css also):

location ~* \.(css|js)$ {
                expires max;
                add_header Pragma public;
                etag off;
                add_header Cache-Control "public";
                add_header Last-Modified "";
                rewrite  "^/(.*)\/(style|script)\.min\.([\d\w]{32})\.(js|css)$" /$1/$2.min.$4 break;

I would guess that the filemtime call does not even require disk access on the server as it should be in linux's file cache. If you have doubts or static html files you can also use a fixed random value (or incremental or content hash) that is updated when your javascript / css preprocessor has finished or let one of your git hooks change it.

In theory you could also use a cachebreaker as a dummy parameter (like /js/script.min.js?cachebreak=0123456789abcfef), but then the file is not cached at least by some proxies because of the "?".

Hey Florian, I have an issue that whenever I deploy the vendor css takes like 3 - 4 minutes to be seen by the app, till then it returns a 401. Would you have a hint why? After like 3 - 4 moments, you keep refreshing the browser and eventually it comes up. This happens with the css files.... you ever see this? How would you solve this? – james emanon May 11, 2020 at 7:47 Do you use some some cdn or a service worker that does cache management? You could try to play around with wget or curl and use any random md5 value. As the nginx config maps ANY 32 character a-f0-9 value to the file, it should be completely independent from the deployment. No matter if it was referenced somewhere. – Florian May 12, 2020 at 8:26 the files that seem to have issue are hashed created via webpack and yes, they are on a cdn. – james emanon May 12, 2020 at 8:49 You can avoid the nginx rules by changing the PHP to use a query string. .../js/script.min.js?x=<?php echo md5(filemtime('/js/script.min.js')) ?> – fidian Sep 24, 2021 at 17:03

Caching is a good thing, but sometimes you want to reloaded file no matter what.

So for this (in production environment) we just define the file version and define that browser should cache that file for a as long as it can.

Ex. myFile.v11.js

For debug environments you would just disable cache in the browser and press force-reload when you would be working on the page.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.