Prefetching Images: When and How to Do It

3/2/2025

High-performing websites are very fast and have minimal latency. A lot of how we perceive a site to be fast is based on how responsive it is to our inputs. Something that can make a website feel lightning fast is when images are able to load instantaneous and the initial loading time of the page is quick. When a user lands on our webpage for the first time, the browser must download all of the javascript, and if you have high-priority images or images inside of the public folder, then the webpage will not fully launch until those downloads are complete. Once the images are fetched, they are stored in the browser cache and are readily available to the user. One of the worst things we can do in terms of performance is to hold the webpage up on its initial load. A long initial load is directly related to early bounces of users and a low SEO. But we want to have our images load as soon as possible as well. We need to have a way where we can have our images stored outside of the public folder to reduce initial load times, but also be able to be cached so they are readily available upon usage. How can we achieve this?


Prefetching images when the use is anticipated is the solution. Prefetching images can be done by initializing an Image instance and setting the src to the url of the image. The way I personally set up my images are either through my S3 buckets or from the CDN it came from if I am just grabbing it off of the internet. If I strategically prefetch these images then we get the best of both worlds-- a fast initial page render and instant retrieval of our images. This is done but choosing the correct time to prefetch our image. For example, if we expect for an image to pop up when a user hovers upon a specific element, then we can create a function to prefetch that image when the user hovers. Here is an example:


const url = "https://example-image-url"
...
const prefetchUrl = () => {
const image = new Image();
image.src = url;
}
... 
<button onMouseEnter={prefetchUrl}>Show Project</button>

When the user hovers over this button, the prefetchUrl function will fire and the browser will perform a get request on the url specified and then cache the image. Now when the user actually clicks the button to show the project the browser will display the cached image instead of making a get request and waiting for the image to arrive.


Another situation we could use this in is if we have image-rich content further down the page and want it to load immediately when the user scrolls to it. In this specific situation, we do not want to lazy load the images since we want to have it immediately available to the user, but we also do not want to fetch the images on the initial load of the application. Although we do not have a hover indicator of a likely future action of the user, we do still have an indicator of scroll position to determine when to start loading the images. Here we can use the IntersectionObserver to manage the scroll position. For example, if the image comes within 200px of the viewport, we can begin requesting the images and caching them in the browser, so that when the user does see them they are fully loaded without sacrificing the initial load time. Here is an implementation for multiple images that appear far towards the bottom of a page.


useEffect(() => {

  const observer = new IntersectionObserver(

    (entries) => {

      entries.forEach((entry) => {

        if (entry.isIntersecting) {

          images.forEach((url) => {

            const img = new Image();

            img.src = url;

          });

        }

      });

    },

    { rootMargin: "200px" } // Preload 200px before entering viewport

  );

  const target = document.querySelector("#image-container");

  if (target) observer.observe(target);
  return () => observer.disconnect();

}, []);

We check to see if the content comes within the specified range, and if it does we prefetch the image. Now the user gets a great experience all around. No waiting around for the initial page load due to many images that we cannot see right away and no waiting around for the images to load when they are to be seen. It is small details like this that can really make a webpage feel ultra-efficient and smooth.


Thank you for reading, and as always I am open to any suggestions, tips, comments, critiques, or feedback in general.

Copy Link
4 / 7
view all blogs