{"id":28346,"date":"2021-04-14T17:29:33","date_gmt":"2021-04-14T17:29:33","guid":{"rendered":"http:\/\/Serving-Remote-Optimized-Images-w-gatsby-image"},"modified":"2025-10-26T02:51:18","modified_gmt":"2025-10-26T09:51:18","slug":"serving-remote-optimized-images-w-gatsby-image","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/","title":{"rendered":"Serving Remote Optimized Images w\/ gatsby-image"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Even though a picture is worth a thousand words, it costs a pretty penny to store and deliver images online. Because of this, many modern web-development tools aim to minimize the impact of images, and other media assets, on site performance.<\/p>\n<p>This post shows you how to build an optimized webpage by leveraging the gatsby-transformer-cloudinary plugin and gatsby-image. We\u2019ll upload local images to a remote content delivery network (Cloudinary), then subsequently source, and transform, the responsive remote images in a GatsbyJS project.<\/p>\n<h2>Sandbox<\/h2>\n<p>We completed this project on Codesandbox, and <a href=\"https:\/\/codesandbox.io\/s\/using-remote-images-in-gatsby-w-gatsby-image-live-yqhxq\">you can find it here<\/a>. You need to provide your Cloudinary credentials as environment variables in the sandbox by creating a <code>.env<\/code> file in the root directory. Specify the environment variables as shown in <code>.env.example<\/code>.<\/p>\n<p><a href=\"https:\/\/codesandbox.io\/s\/using-remote-images-in-gatsby-w-gatsby-image-live-yqhxq\">https:\/\/codesandbox.io\/s\/using-remote-images-in-gatsby-w-gatsby-image-live-yqhxq<\/a><\/p>\n<p>Here are the steps we\u2019ll follow to use remote images in a gatsby project with gatsby-image:<\/p>\n<ol>\n<li>Install Gatsby.js and its dependencies.<\/li>\n<li>Set up the project configuration and layout.<\/li>\n<li>Handle single- or multiple-image queries from Cloudinary through gatsby-transformer-cloudinary.<\/li>\n<li>Optimize the sourced images with Cloudinary and lazy-load them with gatsby-image.<\/li>\n<li>Transform the images using Cloudinary right in the graphql image query.<\/li>\n<li>Design a responsive layout and typography with Chakra-ui.<\/li>\n<\/ol>\n<p>Typically, with gatsby-image, images are stored locally in the project. To utilize external images, a hosted image is required and used with a normal HTML <code>&lt;img\/&gt;<\/code> element. With gatsby-transformer-cloudinary, we can utilize remote images in gatsby-image.<\/p>\n<h2>Prerequisite and Installation<\/h2>\n<p>This project requires knowledge of JavaScript, React, and the basics of Gatsby.js. You install Gatsby.js and other packages with Node.js and its package manager npm, or Yarn, a viable alternative for it.<\/p>\n<p>We install Gatsby.js globally with npm, and create a new project using the command<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">        npm install -g gatsby-cli &amp;&amp; gatsby <span class=\"hljs-keyword\">new<\/span> gtc-demo\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<blockquote>\n<p>To give you a jump-start, Gatsby scaffolds new projects with a starter, which comprises several pages and modules, and we\u2019ll remove them when they\u2019re obsolete.<\/p>\n<\/blockquote>\n<p>We proceed to install the required dependencies using the command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">    <span class=\"hljs-selector-tag\">cd<\/span> <span class=\"hljs-selector-tag\">gtc-demo<\/span> &amp;&amp; <span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-selector-tag\">--save<\/span> <span class=\"hljs-selector-tag\">gatsby-transformer-cloudinary<\/span> <span class=\"hljs-selector-tag\">dotenv<\/span> <span class=\"hljs-keyword\">@chakra-ui<\/span>\/gatsby-plugin @chakra-ui\/react @emotion\/react @emotion\/styled framer-motion\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Project configuration setup<\/h2>\n<p><a href=\"https:\/\/bit.ly\/2v3sy4N\">Sign up for a Cloudinary account<\/a>. Cloudinary offers a free tier, which is more than adequate for small to medium projects.\nOnce signed up, note your cloud name, API key, and API secret for later use.<\/p>\n<p>Gatsby touts two types of plugins:<\/p>\n<ul>\n<li>Source plugins that fetch data from many sources into Gatsby projects.<\/li>\n<li>Transformer plugins that convert sourced data to usable formats.<\/li>\n<\/ul>\n<p>gatsby-transformer-cloudinary uploads images from a local directory to Cloudinary, and transforms the returned image to a format usable by gatsby-image. Cloudinary serves as a drop-in replacement for gatsby-plugin-sharp, and harnesses gatsby-image\u2019s native image-processing capabilities.<\/p>\n<p>Gatsby ships with a configuration file named <code>gatsby-config.js<\/code> in the root of the project. We\u2019ll set up gatsby-transformer-cloudinary, and @chakra-ui\/gatsby-plugin, by updating the array of plugins in <code>gatsby-config.js<\/code>, to include this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">\"dotenv\"<\/span>).config()\n    <span class=\"hljs-built_in\">module<\/span>.exports = {\n      <span class=\"hljs-attr\">siteMetadata<\/span>: {\n        <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">`Gatsby x Cloudinary`<\/span>,\n        <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">`Serve remote images in your Gatsby app using gatsby-image`<\/span>,\n        <span class=\"hljs-attr\">author<\/span>: <span class=\"hljs-string\">`@gatsbyjs`<\/span>\n      },\n      <span class=\"hljs-attr\">plugins<\/span>: &#91;\n        <span class=\"hljs-string\">`gatsby-plugin-react-helmet`<\/span>,\n        {\n          <span class=\"hljs-attr\">resolve<\/span>: <span class=\"hljs-string\">`gatsby-source-filesystem`<\/span>,\n          <span class=\"hljs-attr\">options<\/span>: {\n            <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">`cloudinary-images`<\/span>,\n            <span class=\"hljs-attr\">path<\/span>: <span class=\"hljs-string\">`<span class=\"hljs-subst\">${__dirname}<\/span>\/src\/remote-images`<\/span>\n          }\n        },\n        {\n          <span class=\"hljs-attr\">resolve<\/span>: <span class=\"hljs-string\">\"@chakra-ui\/gatsby-plugin\"<\/span>,\n          <span class=\"hljs-attr\">options<\/span>: {\n            <span class=\"hljs-attr\">isUsingColorMode<\/span>: <span class=\"hljs-literal\">true<\/span>\n          }\n        },\n        {\n          <span class=\"hljs-attr\">resolve<\/span>: <span class=\"hljs-string\">\"gatsby-transformer-cloudinary\"<\/span>,\n          <span class=\"hljs-attr\">options<\/span>: {\n            <span class=\"hljs-attr\">cloudName<\/span>: process.env.CLOUDINARY_CLOUD_NAME,\n            <span class=\"hljs-attr\">apiKey<\/span>: process.env.CLOUDINARY_API_KEY,\n            <span class=\"hljs-attr\">apiSecret<\/span>: process.env.CLOUDINARY_API_SECRET,\n            <span class=\"hljs-attr\">uploadFolder<\/span>: <span class=\"hljs-string\">\"gtc-art-gallery\"<\/span>\n          }\n        }\n      ]\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the configuration file, gatsby-source-filesystem, a source plugin sources file nodes into the Gatsby data layer. Here, we\u2019ve sourced all the images in a folder, which are uploaded once to Cloudinary on build.<\/p>\n<p>We created the <code>remote-images<\/code> folder in the <code>src<\/code> directory of the project, and uploaded all the images into the folder.<\/p>\n<p>We proceed to create a .env file in the project\u2019s root directory, and add our Cloudinary credentials as specified below:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">    <span class=\"hljs-comment\"># Find this at https:\/\/cloudinary.com\/console\/settings\/account<\/span>\n    CLOUDINARY_CLOUD_NAME=xxxxx\n    \n    <span class=\"hljs-comment\"># Generate an API key pair at https:\/\/cloudinary.com\/console\/settings\/security<\/span>\n    CLOUDINARY_API_KEY=xxxxxxxxxxxxxx\n    CLOUDINARY_API_SECRET=xxxxxxxxxxxxxxxxxxx\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we start the development server on <code>localhost:8000<\/code> by running the command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    gatsby develop\n<\/code><\/span><\/pre>\n<p>All the images in the remote-images folder are uploaded to Cloudinary, and added to file nodes for the returned URLs are created in Gatsby\u2019s graphql layer.<\/p>\n<h2>Pages layout design<\/h2>\n<p>The layout.js file in the <code>src\/components<\/code> directory specifies the pages\u2019 design, which persists across the site, and can contain UI elements like headers and footers.<\/p>\n<p>We edit the layout to add a header, which contains the navigation bar and body of the website. First, we import all required dependencies with:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> PropTypes <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"prop-types\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { graphql, useStaticQuery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> Header <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/header\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { Box, Text, Link } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we define the layout component, and fetch the site title defined in gatsby-config.js using <code>useStaticQuery<\/code>, a hook that utilizes Gatsby.js\u2019s StaticQuery API to make GraphQL queries in Gatsby.js components.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">const<\/span> Layout = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ children }<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> data = useStaticQuery(graphql<span class=\"hljs-string\">`\n        query SiteTitleQuery {\n          site {\n            siteMetadata {\n              title\n            }\n          }\n        }\n      `<\/span>)\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Header<\/span> <span class=\"hljs-attr\">siteTitle<\/span>=<span class=\"hljs-string\">{data.site.siteMetadata.title}<\/span> \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{&#91;<\/span>\"<span class=\"hljs-attr\">90<\/span>%\", \"<span class=\"hljs-attr\">90<\/span>%\", \"<span class=\"hljs-attr\">80<\/span>%\"]} <span class=\"hljs-attr\">mx<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">auto<\/span>\"}&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>{children}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Text<\/span> <span class=\"hljs-attr\">mt<\/span>=<span class=\"hljs-string\">{10}<\/span>&gt;<\/span>\n              For this demo, the amazing images here by great artists were all\n              sourced from{\" \"}\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span>\n                <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">https:<\/span>\/\/<span class=\"hljs-attr\">unsplash.com<\/span>\/\"}\n                <span class=\"hljs-attr\">target<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">_blank<\/span>\"}\n                <span class=\"hljs-attr\">color<\/span>=<span class=\"hljs-string\">\"teal.500\"<\/span>\n              &gt;<\/span>\n                Unsplash\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Text<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span><\/span>\n      )\n    }\n    Layout.propTypes = {\n      <span class=\"hljs-attr\">children<\/span>: PropTypes.node.isRequired\n    }\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Layout\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the snippet above<\/p>\n<ul>\n<li>\n<p>The <code>&lt;Header\/&gt;<\/code> custom component represents the navigation bar. Chakra-ui styles the layout with different responsive widths and multiple breakpoints: 90 percent, 90 percent, and 80 percent for mobile, tablet, and desktop devices, respectively.<\/p>\n<\/li>\n<li>\n<p>The <code>mx<\/code> property sets the page\u2019s horizontal-margin property to <code>auto<\/code>, centering the page content regardless of the width.<\/p>\n<\/li>\n<\/ul>\n<p>Next, we add the site title and the navigation bar\u2019s dimensions by updating the <code>Header<\/code> functional component in <code>src\/components\/header.js<\/code>, as follows.<\/p>\n<p>We import the required dependencies, and UI components.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> { Link <span class=\"hljs-keyword\">as<\/span> GatsbyLink } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> PropTypes <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"prop-types\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { Box, Flex, Heading, Text, Button } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we create a <code>Header<\/code> component to render a minimal navigation bar with a menu link.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">const<\/span> Header = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ siteTitle }<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Flex<\/span>\n          <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"nav\"<\/span>\n          <span class=\"hljs-attr\">align<\/span>=<span class=\"hljs-string\">\"center\"<\/span>\n          <span class=\"hljs-attr\">justify<\/span>=<span class=\"hljs-string\">\"space-between\"<\/span>\n          <span class=\"hljs-attr\">wrap<\/span>=<span class=\"hljs-string\">\"wrap\"<\/span>\n          <span class=\"hljs-attr\">px<\/span>=<span class=\"hljs-string\">{&#91;<\/span>\"<span class=\"hljs-attr\">0.5em<\/span>\", \"<span class=\"hljs-attr\">0.5em<\/span>\", \"<span class=\"hljs-attr\">1.5em<\/span>\"]}\n          <span class=\"hljs-attr\">py<\/span>=<span class=\"hljs-string\">{&#91;<\/span>\"<span class=\"hljs-attr\">1em<\/span>\", \"<span class=\"hljs-attr\">1em<\/span>\", \"<span class=\"hljs-attr\">1.5em<\/span>\"]}\n          <span class=\"hljs-attr\">bg<\/span>=<span class=\"hljs-string\">\"blue.900\"<\/span>\n          <span class=\"hljs-attr\">color<\/span>=<span class=\"hljs-string\">\"white\"<\/span>\n        &gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Flex<\/span> <span class=\"hljs-attr\">align<\/span>=<span class=\"hljs-string\">\"flex-start\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"h1\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">GatsbyLink<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">\"\/\"<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">color<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">white.800<\/span>\"}&gt;<\/span>\n                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Text<\/span> <span class=\"hljs-attr\">fontSize<\/span>=<span class=\"hljs-string\">{&#91;<\/span>\"<span class=\"hljs-attr\">md<\/span>\", \"<span class=\"hljs-attr\">md<\/span>\", \"<span class=\"hljs-attr\">lg<\/span>\"]}&gt;<\/span>{siteTitle}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Text<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">GatsbyLink<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Flex<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Flex<\/span> <span class=\"hljs-attr\">align<\/span>=<span class=\"hljs-string\">\"flex-end\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span> <span class=\"hljs-attr\">colorScheme<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">blue<\/span>\"} <span class=\"hljs-attr\">mr<\/span>=<span class=\"hljs-string\">{2}<\/span> <span class=\"hljs-attr\">size<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">sm<\/span>\"}&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">GatsbyLink<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">\"\/\"<\/span>&gt;<\/span>Home<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">GatsbyLink<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Flex<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Flex<\/span>&gt;<\/span><\/span>\n      )\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Lastly, we define the proptypes, the component\u2019s default prop values, and export the <code>Header<\/code> component.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    Header.propTypes = {\n      <span class=\"hljs-attr\">siteTitle<\/span>: PropTypes.string\n    }\n    Header.defaultProps = {\n      <span class=\"hljs-attr\">siteTitle<\/span>: <span class=\"hljs-string\">``<\/span>\n    }\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Header\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We use Chakra-ui components and styles to build a navigation bar, accompanied by the site title and a button to return to the homepage with a click.<\/p>\n<h2>Pages creation<\/h2>\n<p>We have two pages: a page with a responsive banner image, and a page with a <a href=\"https:\/\/cloudinary.com\/guides\/responsive-images\/responsive-image-gallery\">responsive image gallery<\/a>.<\/p>\n<p><strong>Responsive banner image<\/strong>\nIn <code>src\/pages\/index.js<\/code>, we\u2019ll import the required dependencies and make a GraphQL query for a <a href=\"https:\/\/cloudinary.com\/products\/image\">Cloudinary Image<\/a>.<\/p>\n<p>First, we import the required dependencies and make a GraphQL query for the fluid images:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { graphql, Link, useStaticQuery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> Layout <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/layout\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> SEO <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/seo\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> Image <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby-image\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { Box, Button, Heading, Text } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>\n    \n    <span class=\"hljs-keyword\">const<\/span> IndexPage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      <span class=\"hljs-comment\">\/\/ fetch images<\/span>\n      <span class=\"hljs-keyword\">const<\/span> data = useStaticQuery(graphql<span class=\"hljs-string\">`\n        query BannerImage {\n          bannerImage: file(name: { eq: \"7\" }) {\n            cloudinary: childCloudinaryAsset {\n              fluid(transformations: &#91;\"e_grayscale\"], maxWidth: 1500) {\n                ...CloudinaryAssetFluid\n              }\n            }\n          }\n        }\n      `<\/span>)\n      <span class=\"hljs-comment\">\/\/ Assign the returned images to variables.<\/span>\n      <span class=\"hljs-keyword\">const<\/span> bannerImage = data.bannerImage.cloudinary.fluid\n\t\t\t\n\t\t\t<span class=\"hljs-keyword\">return<\/span> (\n\t\t\t\t<span class=\"hljs-comment\">\/\/ component JSX to go in here<\/span>\n\t\t\t)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>useStaticQuery<\/code> hook is for querying the images in this component. The <code>...CloudinaryAssetFluid<\/code> fragment returns a fluid image data that contains aspect ratio, the base64 image, src, sizes, and srcSet. Where we must specify those data fields in a query, fragments take the place of the GraphQL fields.<\/p>\n<p>Just as we added <code>e_grayscale<\/code> transformation in the query, multiple Cloudinary transformations including format and quality types, can be utilized. You can find <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformation_reference\">transformation options here<\/a>.<\/p>\n<p>Next, we return the JSX elements to render the page. The elements are Chakra-ui components.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Layout<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SEO<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Home\"<\/span> \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">mb<\/span>=<span class=\"hljs-string\">{&#91;10,<\/span> <span class=\"hljs-attr\">20<\/span>, <span class=\"hljs-attr\">100<\/span>]}&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">size<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">xl<\/span>\"} <span class=\"hljs-attr\">m<\/span>=<span class=\"hljs-string\">{3}<\/span> <span class=\"hljs-attr\">textAlign<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">center<\/span>\"}&gt;<\/span>\n              Responsive Banner Image\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Image<\/span> <span class=\"hljs-attr\">fluid<\/span>=<span class=\"hljs-string\">{bannerImage}<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Text<\/span> <span class=\"hljs-attr\">my<\/span>=<span class=\"hljs-string\">{5}<\/span>&gt;<\/span>\n            Click any of the buttons below to see the gallery or single Image with\n            the <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span>&gt;<\/span>getFluidImageObject<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">i<\/span>&gt;<\/span> API\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Text<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span> <span class=\"hljs-attr\">colorScheme<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">teal<\/span>\"} <span class=\"hljs-attr\">mr<\/span>=<span class=\"hljs-string\">{10}<\/span> <span class=\"hljs-attr\">mb<\/span>=<span class=\"hljs-string\">{&#91;2,<\/span> <span class=\"hljs-attr\">0<\/span>, <span class=\"hljs-attr\">0<\/span>]}&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">\"\/gallery\"<\/span>&gt;<\/span> Gallery Images<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Layout<\/span>&gt;<\/span><\/span>\n      )\n    }\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> IndexPage \n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We pass the fluid image data to the gatsby-image <code>&lt;Image\/&gt;<\/code> component to render the image.<\/p>\n<p>To see the lazy loading in action, we refresh the page or look in the browser\u2019s network tab. Since subsequent refreshes returned cached image versions, we have to do a hard refresh of the page or throttle the network to spot the lazy loading.<\/p>\n<p><strong>Gallery Images<\/strong>\nLike the single responsive image, we\u2019ll create a page by creating a file in the src\/pages directory called <code>gallery.js<\/code>. Gatsby.js handles the automatic page creation of any file added to the <code>src\/pages<\/code> directory.<\/p>\n<p>We proceed to import the required dependencies and query all the uploaded images.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> Image <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby-image\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { Box, Heading, SimpleGrid } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { graphql, useStaticQuery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> Layout <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/layout\"<\/span>\n    <span class=\"hljs-keyword\">import<\/span> SEO <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/seo\"<\/span>\n    \n    <span class=\"hljs-keyword\">const<\/span> SinglePage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> data = useStaticQuery(graphql<span class=\"hljs-string\">`\n        query GalleryImages {\n          listImages: allCloudinaryAsset(limit: 9) {\n            images: edges {\n              node {\n                fluid {\n                  ...CloudinaryAssetFluid\n                }\n              }\n            }\n          }\n        }\n      `<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> galleryImages = data.listImages.images\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we render the image gallery component using <code>SimpleGrid<\/code> &#8211;  a Chakra-ui components to create grids using CSS-grid.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Layout<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SEO<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">single<\/span>\"} \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">mx<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">auto<\/span>\"} <span class=\"hljs-attr\">my<\/span>=<span class=\"hljs-string\">{10}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">textAlign<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">center<\/span>\"} <span class=\"hljs-attr\">size<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">xl<\/span>\"} <span class=\"hljs-attr\">mb<\/span>=<span class=\"hljs-string\">{10}<\/span>&gt;<\/span>\n              Optimized Gallery Images\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SimpleGrid<\/span> <span class=\"hljs-attr\">columns<\/span>=<span class=\"hljs-string\">{&#91;1,<\/span> <span class=\"hljs-attr\">2<\/span>, <span class=\"hljs-attr\">3<\/span>]} <span class=\"hljs-attr\">spacing<\/span>=<span class=\"hljs-string\">{2}<\/span>&gt;<\/span>\n              {galleryImages.map((val, index) =&gt; (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>\n                  <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span>\n                  <span class=\"hljs-attr\">p<\/span>=<span class=\"hljs-string\">{3}<\/span>\n                  <span class=\"hljs-attr\">m<\/span>=<span class=\"hljs-string\">{2}<\/span>\n                  <span class=\"hljs-attr\">my<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">auto<\/span>\"}\n                  <span class=\"hljs-attr\">shadow<\/span>=<span class=\"hljs-string\">\"md\"<\/span>\n                  <span class=\"hljs-attr\">borderWidth<\/span>=<span class=\"hljs-string\">\"1px\"<\/span>\n                  <span class=\"hljs-attr\">rounded<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">lg<\/span>\"}\n                &gt;<\/span>\n                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Image<\/span> <span class=\"hljs-attr\">fluid<\/span>=<span class=\"hljs-string\">{val.node.fluid}<\/span> \/&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n              ))}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SimpleGrid<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Layout<\/span>&gt;<\/span><\/span>\n      )\n    }\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> SinglePage\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Using Chakra-ui components, we loop through the returned list of fluid images and render each in a gatsby-image component.<\/p>\n<p>You can see the <a href=\"https:\/\/yqhxq-8000.sse.codesandbox.io\">final result here<\/a>, and the pages look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_731E13D2EA2895424272451DEB918E30F425FBA88FEFE5FAD0E640C3A20B33CB_1613735043084_cl-mediajams-1.gif\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"848\" height=\"914\"\/><\/p>\n<p>How about we look at how to use remote Images in gatsby-image without the GraphQL query overhead? We\u2019ll discuss that in a subsequent post.<\/p>\n<h2>Summary<\/h2>\n<p>In this post, we saw how to utilize remote optimized images from Cloudinary in a Gatsby site. We render the images using Gatsby.js\u2019s gatsby-image component to provide performance optimizations during the site\u2019s build process.<\/p>\n<p>You may find these resources useful.<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/chakra-ui.com\/docs\/getting-started\">Chakra-ui Documentation<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/www.npmjs.com\/package\/gatsby-transformer-cloudinary\">Gatsby-transformer-cloudinary<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28347,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[378,134,175,371],"class_list":["post-28346","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-gatsbyjs","tag-guest-post","tag-jamstack","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Serving Remote Optimized Images w\/ gatsby-image<\/title>\n<meta name=\"description\" content=\"In this jam, we discuss how to utilize optimized remote images in a Gatsby.js project while utilizing gatsby-image&#039;s performance benefits.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Serving Remote Optimized Images w\/ gatsby-image\" \/>\n<meta property=\"og:description\" content=\"In this jam, we discuss how to utilize optimized remote images in a Gatsby.js project while utilizing gatsby-image&#039;s performance benefits.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-04-14T17:29:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-26T09:51:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"4456\" \/>\n\t<meta property=\"og:image:height\" content=\"3565\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Serving Remote Optimized Images w\/ gatsby-image\",\"datePublished\":\"2021-04-14T17:29:33+00:00\",\"dateModified\":\"2025-10-26T09:51:18+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\"},\"wordCount\":6,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA\",\"keywords\":[\"GatsbyJS\",\"Guest Post\",\"JAMStack\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2021\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\",\"name\":\"Serving Remote Optimized Images w\/ gatsby-image\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA\",\"datePublished\":\"2021-04-14T17:29:33+00:00\",\"dateModified\":\"2025-10-26T09:51:18+00:00\",\"description\":\"In this jam, we discuss how to utilize optimized remote images in a Gatsby.js project while utilizing gatsby-image's performance benefits.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA\",\"width\":4456,\"height\":3565},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Serving Remote Optimized Images w\/ gatsby-image\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Serving Remote Optimized Images w\/ gatsby-image","description":"In this jam, we discuss how to utilize optimized remote images in a Gatsby.js project while utilizing gatsby-image's performance benefits.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/","og_locale":"en_US","og_type":"article","og_title":"Serving Remote Optimized Images w\/ gatsby-image","og_description":"In this jam, we discuss how to utilize optimized remote images in a Gatsby.js project while utilizing gatsby-image's performance benefits.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/","og_site_name":"Cloudinary Blog","article_published_time":"2021-04-14T17:29:33+00:00","article_modified_time":"2025-10-26T09:51:18+00:00","og_image":[{"width":4456,"height":3565,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/"},"author":{"name":"","@id":""},"headline":"Serving Remote Optimized Images w\/ gatsby-image","datePublished":"2021-04-14T17:29:33+00:00","dateModified":"2025-10-26T09:51:18+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/"},"wordCount":6,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA","keywords":["GatsbyJS","Guest Post","JAMStack","Under Review"],"inLanguage":"en-US","copyrightYear":"2021","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/","name":"Serving Remote Optimized Images w\/ gatsby-image","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA","datePublished":"2021-04-14T17:29:33+00:00","dateModified":"2025-10-26T09:51:18+00:00","description":"In this jam, we discuss how to utilize optimized remote images in a Gatsby.js project while utilizing gatsby-image's performance benefits.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA","width":4456,"height":3565},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/serving-remote-optimized-images-w-gatsby-image\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Serving Remote Optimized Images w\/ gatsby-image"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924738\/Web_Assets\/blog\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182\/6e0eaca43160e7b9657ac27765de11965d48de22-4456x3565-1_28347b3182.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28346","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28346"}],"version-history":[{"count":3,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28346\/revisions"}],"predecessor-version":[{"id":38992,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28346\/revisions\/38992"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28347"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28346"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28346"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28346"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}