
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Wed, 08 Apr 2026 06:46:09 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Modernizing the toolbox for Cloudflare Pages builds]]></title>
            <link>https://blog.cloudflare.com/moderizing-cloudflare-pages-builds-toolbox/</link>
            <pubDate>Wed, 17 May 2023 13:00:37 GMT</pubDate>
            <description><![CDATA[ A new beta build system is now available for Cloudflare Pages. We've updated our default languages and tools, and made some exciting underlying architecture changes. You can enable it in your project settings in the dashboard today. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2lME1CWawsCQtIuzvvfLPq/b037a9c82151e6976cb0ed220573ad80/image2-22.png" />
            
            </figure><p>Cloudflare Pages <a href="/cloudflare-pages/">launched</a> over two years ago in December 2020, and since then, we have grown Pages to build millions of deployments for developers. In May 2022, to support developers with more complex requirements, we opened up Pages to empower developers to <a href="/cloudflare-pages-direct-uploads/">create deployments using their own build environments</a> — but that wasn't the end of our journey. Ultimately, we want to be able to allow anyone to use our build platform and take advantage of the git integration we offer. You should be able to connect your repository and have it <i>just work</i> on Cloudflare Pages.</p><p>Today, we're introducing a new beta version of our build system (a.k.a. "build image") which brings the default set of tools and languages up-to-date, and sets the stage for future improvements to builds on Cloudflare Pages. We now support the latest versions of Node.js, Python, Hugo and many more, putting you on the best path for any new projects that you undertake. Existing projects will continue to use the current build system, but this upgrade will be available to opt-in for everyone.</p>
    <div>
      <h2>New defaults, new possibilities</h2>
      <a href="#new-defaults-new-possibilities">
        
      </a>
    </div>
    <p>The Cloudflare Pages build system has been updated to not only support new versions of your favorite languages and tools, but to also include new versions by default. The versions of 2020 are no longer relevant for the majority of today's projects, and as such, we're bumping these to their more modern equivalents:</p><ul><li><p><b>Node.js</b>' default is being increased from 12.18.0 to 18.16.0,</p></li><li><p><b>Python</b> 2.7.18 and 3.10.5 are both now available by default,</p></li><li><p><b>Ruby</b>'s default is being increased from 2.7.1 to 3.2.2,</p></li><li><p><b>Yarn</b>'s default is being increased from 1.22.4 to 3.5.1,</p></li><li><p>And we're adding <b>pnpm</b> with a default version of 8.2.0.</p></li></ul><p>These are just some of the headlines — check out <a href="https://developers.cloudflare.com/pages/platform/language-support-and-tools/">our documentation</a> for the full list of changes.</p><p>We're aware that these new defaults constitute a breaking change for anyone using a project without pinning their versions with an environment variable or version file. That's why we're making this new build system opt-in for existing projects. You'll be able to stay on the existing system without breaking your builds. If you do decide to adventure with us, we make it easy to test out the new system in your preview environments before rolling out to production.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/265Kkauu3hg7i7PgW6l9IC/ac785539cffcfd46c52ca0e01b70b306/image5-5.png" />
            
            </figure><p>Additionally, we're now making your builds more reproducible by taking advantage of lockfiles with many package managers. <code>npm ci</code> and <code>yarn --pure-lockfile</code> are now used ahead of your build command in this new version of the build system.</p><p>For new projects, these updated defaults and added support for pnpm and Yarn 3 mean that more projects will just work immediately without any undue setup, tweaking, or configuration. Today, we're launching this update as a beta, but we will be quickly promoting it to general availability once we're satisfied with its stability. Once it does graduate, new projects will use this updated build system by default.</p><p>We know that this update has been a long-standing request from our users (we thank you for your patience!) but part of this rollout is ensuring that we are now in a better position to make regular updates to Cloudflare Pages' build system. You can expect these default languages and tools to now keep pace with the rapid rate of change seen in the world of web development.</p><p>We very much welcome your continued feedback as we know that new tools can quickly appear on the scene, and old ones can just as quickly drop off. As ever, our <a href="https://discord.com/invite/cloudflaredev">Discord server</a> is the best place to engage with the community and Pages team. We’re excited to hear your thoughts and suggestions.</p>
    <div>
      <h2>Our modular and scalable architecture</h2>
      <a href="#our-modular-and-scalable-architecture">
        
      </a>
    </div>
    <p>Powering this updated build system is a new architecture that we've been working on behind-the-scenes. <a href="/cloudflare-pages-build-improvements/">We're no strangers to sweeping changes of our build infrastructure</a>: we've done a lot of work to grow and scale our infrastructure. Moving beyond purely <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">static site hosting</a> with <a href="/cloudflare-pages-goes-full-stack/">Pages Functions</a> brought a new wave of users, and as we explore <a href="/pages-and-workers-are-converging-into-one-experience">convergence</a> with Workers, we expect even more developers to rely on our git integrations and CI builds. Our new architecture is being rolled out without any changes affecting users, so unless you're interested in the technical nitty-gritty, feel free to stop reading!</p><p>The biggest change we're making with our architecture is its modularity. Previously, we were using Kubernetes to run a monolithic container which was responsible for everything for the build. Within the same image, we'd stream our build logs, clone the git repository, install any custom versions of languages and tools, install a project's dependencies, run the user's build command, and upload all the assets of the build. This was a lot of work for one container! It meant that our system tooling had to be compatible with versions in the user's space and therefore new default versions were a massive change to make. This is a big part of why it took us so long to be able to update the build system for our users.</p><p>In the new architecture, we've broken these steps down into multiple separate containers. We make use of <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/">Kubernetes' init containers feature</a> and instead of one monolithic container, we have three that execute sequentially:</p><ol><li><p>clone a user's git repository,</p></li><li><p>install any custom versions of languages and tools, install a project's dependencies, run the user's build command, and</p></li><li><p>upload all the assets of a build.</p></li></ol><p>We use a <a href="https://kubernetes.io/docs/tasks/access-application-cluster/communicate-containers-same-pod-shared-volume/">shared volume</a> to give the build a persistent workspace to use between containers, but now there is clear isolation between <b>system</b> stages (cloning a repository and uploading assets) and <b>user</b> stages (running code that the user is responsible for). We no longer need to worry about conflicting versions, and we've created an additional layer of security by isolating a user's control to a separate environment.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/11McSSl7sZWok1UdR8EuRV/35bb07d37152065d5870c24813ac8d73/1-6.png" />
            
            </figure><p>We're also aligning the final stage, the one responsible for uploading static assets, with the same APIs that Wrangler uses for Direct Upload projects. This reduces our maintenance burden going forward since we'll only need to consider one way of uploading assets and creating deployments. As we consolidate, we're exploring ways to make these APIs even faster and more reliable.</p>
    <div>
      <h3>Logging out</h3>
      <a href="#logging-out">
        
      </a>
    </div>
    <p>You might have noticed that we haven't yet talked about how we're continuing to stream build logs. Arguably, this was one of the most challenging pieces to work out. When everything ran in a single container, we were able to simply latch directly into the <code>stdout</code> of our various stages and pipe them through to a Durable Object which could communicate with the Cloudflare dashboard.</p><p>By introducing this new isolation between containers, we had to get a bit more inventive. After prototyping a number of approaches, we've found one that we like. We run a separate, global log collector container inside Kubernetes which is responsible for collating logs from a build, and passing them through to that same Durable Object infrastructure. The one caveat is that the logs now need to be annotated with which build they are coming from, since one global log collector container accepts logs from multiple builds. A Worker in front of the Durable Object is responsible for reading the annotation and delegating to the relevant build's Durable Object instance.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6liD6t03jOlyaUug44A7gQ/9e6fec6d6b8864b187353872d9744cd4/image1-40.png" />
            
            </figure>
    <div>
      <h3>Caching in</h3>
      <a href="#caching-in">
        
      </a>
    </div>
    <p>With this new modular architecture, we plan to integrate a feature we've been teasing for a while: build caching. Today, when you run a build in Cloudflare Pages, we start fresh every time. This works, but it's inefficient.</p><p>Very often, only small changes are actually made to your website between deployments: you might tweak some text on your homepage, or add a new blog post; but rarely does the core foundation of your site actually change between deployments. With build caching, we can reuse some of the work from earlier builds to speed up subsequent builds. We'll offer a best-effort storage mechanism that allows you to persist and restore files between builds. You'll soon be able to cache dependencies, as well as the build output itself if your framework supports it, resulting in considerably faster builds and a tighter feedback loop from push to deploy.</p><p>This is possible because our new modular design has clear divides between the stages where we'd want to restore and cache files.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/YcQdgswXh6aueVEkJkBGK/020e5a74f78b9c8a961cda57c623c69c/2-3.png" />
            
            </figure>
    <div>
      <h2>Start building</h2>
      <a href="#start-building">
        
      </a>
    </div>
    <p>We're excited about the improvements that this new modular architecture will afford the Pages team, but we're even more excited for how this will result in faster and more scalable builds for our users. This architecture transition is rolling out behind-the-scenes, but <b>the updated beta build system with new languages and tools is available to try today</b>. Navigate to your Pages project settings in the Cloudflare Dashboard to opt-in.</p><p>Let us know if you have any feedback on the <a href="https://discord.com/invite/cloudflaredev">Discord server</a>, and stay tuned for more information about build caching in upcoming posts on this blog. Later today (Wednesday 17th, 2023), the Pages team will be hosting a <a href="https://discord.com/invite/cloudflaredev?event=1103324690149298196">Q&amp;A session</a> to talk about this announcement on Discord at 17:30 UTC.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">3CewNJiFa5g7gsagtQab5V</guid>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
        <item>
            <title><![CDATA[And here's another one: the Next.js Edge Runtime becomes the fourth full-stack framework supported by Cloudflare Pages]]></title>
            <link>https://blog.cloudflare.com/next-on-pages/</link>
            <pubDate>Mon, 24 Oct 2022 13:00:00 GMT</pubDate>
            <description><![CDATA[ You can now deploy SSR Next.js applications to the Cloudflare Pages platform ⚡️ ]]></description>
            <content:encoded><![CDATA[ <p></p><p>You can now deploy <a href="https://nextjs.org/">Next.js</a> applications which opt in to the <a href="https://nextjs.org/docs/api-reference/edge-runtime">Edge Runtime</a> on Cloudflare Pages. Next.js is the fourth full-stack web framework that the Pages platform officially supports, and it is <a href="https://almanac.httparchive.org/en/2022/jamstack">one of the most popular in the 'Jamstack-y' space</a>.</p><p>Cloudflare Pages started its journey as a platform for static websites, but with <a href="/cloudflare-pages-goes-full-stack/">last year's addition of Pages Functions</a> powered by Cloudflare Workers, the platform has progressed to support an even more diverse range of use cases. Pages Functions allows developers to sprinkle in small pieces of server-side code with its simple file-based routing, or, as we've seen with the adoption from other frameworks (namely <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site/">SvelteKit</a>, <a href="https://developers.cloudflare.com/pages/framework-guides/remix/">Remix</a> and <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-qwik-site/">Qwik</a>), Pages Functions can be used to power your entire full-stack app. The folks behind <a href="/remix-on-cloudflare-pages/">Remix previously talked about the advantages of adopting open standards</a>, and we've seen this again with Next.js' Edge Runtime.</p>
    <div>
      <h2>Next.js' Edge Runtime</h2>
      <a href="#next-js-edge-runtime">
        
      </a>
    </div>
    <p><a href="https://nextjs.org/docs/api-reference/edge-runtime">Next.js' Edge Runtime</a> is an experimental mode that developers can opt into which results in a different type of application being built. Previously, Next.js applications which relied on server-side rendering (SSR) functionality had to be deployed on a Node.js server. Running a Node.js server has significant overhead, and our Cloudflare Workers platform was fundamentally built on a different technology, <a href="https://developers.cloudflare.com/workers/learning/how-workers-works/">V8</a>.</p><p>However, when Next.js <a href="https://vercel.com/blog/introducing-the-edge-runtime">introduced the Edge Runtime mode</a> in June 2022, we saw the opportunity to bring this widely used framework to our platform. We're very excited that this is being developed in coordination with the <a href="/introducing-the-wintercg/">WinterCG</a> standards to ensure interoperability across the various web platforms and to ensure that developers have the choice on where they run their business, without fearing any significant vendor lock-in.</p><p>It’s important to note that some existing Next.js apps built for Node.js won't immediately work on Pages. If your application relies on any Node.js built-ins or long-running processes, then Pages may not support your app with today’s announcement as we're working on <a href="/node-js-support-cloudflare-workers/">expanding our support for Node.js</a>.</p><p>However, we see the migration to the Edge Runtime as an effort that's worthy of investment, to run your applications, well, on the edge! These applications are cheaper to run, respond faster to users and have the latest features that full-stack frameworks offer. We're seeing increased interest in third-party npm packages and libraries that support standardized runtimes, and in combination with Cloudflare's data products (e.g. <a href="https://www.cloudflare.com/products/workers-kv/">KV</a>, <a href="https://www.cloudflare.com/products/durable-objects/">Durable Objects</a> and <a href="/whats-new-with-d1/">D1</a>), we're confident that the edge is going to be the first place that people will want to deploy applications going forward.</p>
    <div>
      <h2>Deploy your Next.js app to Cloudflare Pages</h2>
      <a href="#deploy-your-next-js-app-to-cloudflare-pages">
        
      </a>
    </div>
    <p>Let’s walk through an example, creating a new Next.js application that opts into this Edge Runtime and deploying it to Cloudflare Pages.</p>
            <pre><code>npx create-next-app@latest my-app</code></pre>
            <p>This will create a new Next.js app in the <code>my-app</code> folder. The default template comes with a traditional Node.js powered API route, so let's update that to instead use the Edge Runtime.</p>
            <pre><code>// pages/api/hello.js

// Next.js Edge API Routes: https://nextjs.org/docs/api-routes/edge-api-routes

export const config = {
  runtime: 'experimental-edge',
}

export default async function (req) {
  return new Response(
    JSON.stringify({ name: 'John Doe' }),
    {
      status: 200,
      headers: {
        'Content-Type': 'application/json'
      }
    }
  )
}</code></pre>
            <p>Thanks to the Edge Runtime adopting the Web API standards, if you've ever written a Cloudflare Worker before, this might look familiar.</p><p>Next, we can update the global <code>next.config.js</code> configuration file to use the Edge Runtime. This will enable us to use <a href="https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props">the <code>getServerSideProps()</code> API</a> and server-side render (SSR) our webpages.</p>
            <pre><code>// next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    runtime: 'experimental-edge',
  },
  reactStrictMode: true,
  swcMinify: true,
}
module.exports = nextConfig</code></pre>
            <p>Finally, we're ready to deploy the project. Publish it to a GitHub or GitLab repository, create a new Pages project, and select "Next.js" from the list of framework presets. This will configure your project to use <a href="https://github.com/cloudflare/next-on-pages">the <code>@cloudflare/next-on-pages</code> CLI</a> which builds and transforms your project into something we can deploy on Pages. Navigate to the project settings and add an environment variable, <code>NODE_VERSION</code> set to <code>14</code> or greater, as well as the following compatibility flags: <code>streams_enable_constructors</code> and <code>transformstream_enable_standard_constructor</code>. You should now be able to deploy your Next.js application. If you want to read more, you can find a detailed guide in <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nextjs-site/">our documentation</a>.</p>
    <div>
      <h2>How it runs on Cloudflare Pages</h2>
      <a href="#how-it-runs-on-cloudflare-pages">
        
      </a>
    </div>
    
    <div>
      <h3>Compatibility Dates and Compatibility Flags</h3>
      <a href="#compatibility-dates-and-compatibility-flags">
        
      </a>
    </div>
    <p>Cloudflare Workers has solved the versioning problem by <a href="/backwards-compatibility-in-cloudflare-workers/">introducing compatibility dates and compatibility flags</a>. While it has been in beta, Pages Functions has always defaulted to using the oldest version of the Workers runtime. We've now introduced controls to allow developers to set these dates and flags on their Pages projects environments.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1qm1x1OaVxhfm80IgIBhYd/e7bff63f0f14ee4a08ea82b14f3c8a53/image2-12.png" />
            
            </figure><p>By keeping this date recent, you are able to opt in to the latest features and bug fixes that the Cloudflare Workers runtime offers, but equally, you're completely free to keep the date on whatever works for you today, and we'll continue to support the functionality at that point in time, forever. We also allow you to set these dates for your production and preview environments independently which will let you test these changes out safely in a preview deployment before rolling it out in production.</p><p>We've been working on adding more support for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Streams_API">Streams API</a> to the Workers Runtime, and some of this functionality is gated behind the flags we added to the project earlier. <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates/#change-history">These flags are currently scheduled to graduate</a> and become on-by-default on a future compatibility date, 2022-11-30.</p>
    <div>
      <h3>The <code>@cloudflare/next-on-pages</code> CLI</h3>
      <a href="#the-cloudflare-next-on-pages-cli">
        
      </a>
    </div>
    <p>Vercel introduced the <a href="https://vercel.com/blog/build-output-api">Build Output API</a> in July 2022 as a "zero configuration" directory structure which the Vercel platform inherently understands and can deploy. We've decided to hook into this same API as a way to build Next.js projects consistently that we can understand and deploy.</p><p>The <a href="https://github.com/cloudflare/next-on-pages">open-source</a> <code>[@cloudflare/next-on-pages](https://github.com/cloudflare/next-on-pages)</code> <a href="https://github.com/cloudflare/next-on-pages">CLI</a> runs <code>npx vercel build</code> behind the scenes, which produces a <code>.vercel/output</code> directory. This directory conforms to the <a href="https://vercel.com/docs/build-output-api/v3">Build Output API</a>, and of particular interest, contains a <code>config.json</code>, <code>static</code> folder and folder of <code>functions</code>. The <code>@cloudflare/next-on-pages</code> CLI then parses this <code>config.json</code> manifest, and combines all the <code>functions</code> into a single <a href="https://developers.cloudflare.com/pages/platform/functions/#advanced-mode">Pages Functions 'advanced mode' <code>_worker.js</code></a>.</p><p>At this point, the build is finished. Pages then automatically picks up this <code>_worker.js</code> and deploys it with Pages Functions atop the <code>static</code> directory.</p><p>Although currently just an implementation detail, we opted to use this Build Output API for a number of reasons. We’re also exploring other similar functionality natively on the Pages platform. We already have one "magical" directory, the <code>functions</code> directory which we use for the file-based routing of Pages Functions. It's possible that we offer other fixed directory structures which would reduce the need for configuration of any projects using frameworks which adopt the API. Let us know <a href="https://discord.com/channels/595317990191398933/910978223968518144">in Discord</a> if you have any thoughts or preferences on what you would like to see!</p><p>Additionally, if more full-stack frameworks do adopt Vercel's Build Output API, we may have automatic support for them running on Pages with this CLI. We've only been experimenting with Next.js here so far (and SvelteKit, Remix and Qwik all have their own way of building their projects on Pages at the moment), but it's possible that in the future we may converge on a standard approach which could be shared between frameworks and platforms. We're excited to see how this might transpire. Again, <a href="https://discord.com/channels/595317990191398933/910978223968518144">let us know</a> if you have thoughts!</p>
    <div>
      <h3>Experimental webpack minification</h3>
      <a href="#experimental-webpack-minification">
        
      </a>
    </div>
    <p>As part of the compilation from <code>.vercel/output/functions</code> to an <code>_worker.js</code>, the <code>@cloudflare/next-on-pages</code> CLI can perform an experimental minification to give you more space for your application to run on Workers. Right now, most accounts are <a href="https://developers.cloudflare.com/workers/platform/limits/#worker-size">limited to a maximum script size of 1MB</a> (although this can be raised in some circumstances—<a href="https://docs.google.com/forms/d/e/1FAIpQLSd_fwAVOboH9SlutMonzbhCxuuuOmiU1L_I5O2CFbXf_XXMRg/viewform">get in touch</a>!). You can ordinarily fit quite a lot of code in this, but one thing notable about Next.js' build process at the moment is that it creates webpack-compiled, fully-formed and fully-isolated functions scripts in each of the directories in <code>.vercel/output/functions</code>. This means that each function ends up looking something like this:</p>
            <pre><code>let _ENTRIES = {};
(() =&gt; {
  // webpackBootstrap
})();

(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([100], {

  123: (() =&gt; {
    // webpack chunk #123
  }),
  234: (() =&gt; {
    // webpack chunk #234
  }),
  345: (() =&gt; {
    // webpack chunk #345
  }),

  // …lots of webpack chunks…

}, () =&gt; {
  // webpackRuntimeModules
}]);

export default {
  async fetch(request, env, ctx) {
    return _ENTRIES['some_function'].default.call(request);
  }
}</code></pre>
            <p>The script contains everything that's needed to deploy this function, and most of the logic exists in these webpack chunks, but that means that each function has a lot of code shared with its siblings. Quickly, you'll reach the 1MB limit, if you naively deployed all these functions together.</p><p>Our <code>@cloudflare/next-on-pages --experimental-minify</code> CLI argument deals with this problem by analyzing webpack chunks which are re-used in multiple places in this <code>.vercel/output/functions</code> directory and extracts out that code to a common place. This allows our compiler (esbuild) to efficiently combine this code, without duplicating it in all of these places. This process is experimental for the time being, while we look to make this as efficient as possible, without introducing any bugs as a result. Please <a href="https://github.com/cloudflare/next-on-pages/issues/">file an issue on GitHub</a> if you notice any difference in behavior when using <code>--experimental-minify</code>.</p>
    <div>
      <h2>What's next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>Pages Functions has been in beta for almost a year, and we're very excited to say that general availability is just around the corner. We're polishing off the last of the remaining features which includes analytics, logging, and billing. In fact, for billing, we recently made <a href="https://developers.cloudflare.com/pages/platform/functions/billing/">the announcement of how you'll be able to use the Workers Paid plan to remove the request limits of the Pages Functions beta from November 15</a>.</p><p>Finally, we're also looking at how we can bring Wasm support to Pages Functions which will unlock ever more use-cases for your full-stack applications. Stay tuned for more information on how we'll be offering this soon.</p><p>Try creating a Next.js Edge Runtime application and deploying it to Cloudflare Pages with the example above or by following <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nextjs-site/">the guide in our documentation</a>. Let us know if you have any questions or face any issues in <a href="https://discord.com/channels/595317990191398933/910978223968518144">Discord</a> or on <a href="https://github.com/cloudflare/next-on-pages/issues/">GitHub</a>, and please report any quirks of the <code>--experimental-minify</code> argument. As always, we're excited to see what you build!</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Full Stack]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Connectivity Cloud]]></category>
            <guid isPermaLink="false">6H5XhDzpuEfNdN2fJj9PO2</guid>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Pages gets even faster with Early Hints]]></title>
            <link>https://blog.cloudflare.com/early-hints-on-cloudflare-pages/</link>
            <pubDate>Fri, 07 Oct 2022 13:00:00 GMT</pubDate>
            <description><![CDATA[ Announcing support for sending Early Hints from your Cloudflare Pages projects ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Last year, we demonstrated what we meant by “lightning fast”, <a href="/cloudflare-pages-is-lightning-fast/">showing Pages' first-class performance</a> in all parts of the world, and today, we’re thrilled to announce an integration that takes this commitment to speed even further – introducing Pages support for Early Hints! Early Hints allow you to unblock the loading of page critical resources, ahead of any slow-to-deliver HTML pages. Early Hints can be used to improve the loading experience for your visitors by significantly reducing key performance metrics such as the largest contentful paint (LCP).</p>
    <div>
      <h2>What is Early Hints?</h2>
      <a href="#what-is-early-hints">
        
      </a>
    </div>
    <p><a href="/early-hints/">Early Hints</a> is a new feature of the Internet which is <a href="https://developer.chrome.com/blog/early-hints/#implementing-early-hints">supported in Chrome since version 103</a>, and that <a href="/early-hints-performance/">Cloudflare made generally available</a> for websites using our network. Early Hints supersedes <a href="https://groups.google.com/a/chromium.org/g/blink-dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ">Server Push</a> as a mechanism to "hint" to a browser about critical resources on your page (e.g. fonts, CSS, and above-the-fold images). The browser can immediately start loading these resources before waiting for a full HTML response. This uses time that was otherwise previously wasted! Before Early Hints, no work could be started until the browser received the first byte of the response. Now, the browser can fill this time usefully when it was previously sat waiting. Early Hints can bring significant improvements to the performance of your website, particularly for metrics such as LCP.</p>
    <div>
      <h3>How Early Hints works</h3>
      <a href="#how-early-hints-works">
        
      </a>
    </div>
    <p>Cloudflare caches any <code>preload</code> and <code>preconnect</code> type <code>Link</code> headers sent from your 200 OK response, and sends them early for any subsequent requests as a 103 Early Hints response.</p><p>In practical terms, an HTTP conversation now looks like this:</p><p><b>Request</b></p>
            <pre><code>GET /
Host: example.com</code></pre>
            <p><b>Early Hints Response</b></p>
            <pre><code>103 Early Hints
Link: &lt;/styles.css&gt;; rel=preload; as=style</code></pre>
            <p><b>Response</b></p>
            <pre><code>200 OK
Content-Type: text/html; charset=utf-8
Link: &lt;/styles.css&gt;; rel=preload; as=style

&lt;html&gt;
&lt;!-- ... --&gt;
&lt;/html&gt;</code></pre>
            
    <div>
      <h2>Early Hints on Cloudflare Pages</h2>
      <a href="#early-hints-on-cloudflare-pages">
        
      </a>
    </div>
    <p>Websites hosted on Cloudflare Pages can particularly benefit from Early Hints. If you're using <a href="/cloudflare-pages-goes-full-stack/">Pages Functions</a> to generate dynamic server-side rendered (SSR) pages, there's a good chance that Early Hints will make a significant improvement on your website.</p>
    <div>
      <h3>Performance Testing</h3>
      <a href="#performance-testing">
        
      </a>
    </div>
    <p>We created a simple demonstration e-commerce website in order to evaluate the performance of Early Hints.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/77w2Mw6t1Oku0C2uFulZvH/09416e738ac559f7977e8d76614ad0af/image2-7.png" />
            
            </figure><p>This landing page has the price of each item, as well as a remaining stock counter. The page itself is just hand-crafted HTML and CSS, but these pricing and inventory values are being templated in live for every request with <a href="https://developers.cloudflare.com/pages/platform/functions/">Pages Functions</a>. To simulate loading from an external data-source (possibly backed by <a href="https://developers.cloudflare.com/workers/runtime-apis/kv/">KV</a>, <a href="https://developers.cloudflare.com/workers/runtime-apis/durable-objects/">Durable Objects</a>, <a href="/introducing-d1/">D1</a>, or even an external API like Shopify) we've added a fixed delay before this data resolves. We include <code>preload</code> links in our response to some critical resources:</p><ul><li><p>an external CSS stylesheet,</p></li><li><p>the image of the t-shirt,</p></li><li><p>the image of the cap,</p></li><li><p>and the image of the keycap.</p></li></ul><p>The very first request makes a waterfall like you might expect. The first request is held blocked for a considerable amount of time while we resolve this pricing and inventory data. Once loaded, the browser parses the HTML, pulls out the external resources, and makes subsequent requests for their contents. The CSS and images extend the loading time considerably given their large dimensions and high quality. The largest contentful paint (LCP) occurs when the t-shirt image loads, and the document finishes once all requests are fulfilled.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/24N9FzqlRfCtlSGuPlUPic/8650a76a958f4946e20c6680cb01ac84/image1-10.png" />
            
            </figure><p>Subsequent requests are where things get interesting! These <code>preload</code> links are cached on Cloudflare's global network, and are sent ahead of the document in a 103 Early Hints response. Now, the waterfall looks much different. The initial request goes out the same, but now, requests for the CSS and images slide much further left since they can be started as soon as the 103 response is delivered. The browser starts fetching those resources while waiting for the original request to finish server-side rendering. The LCP again occurs once the t-shirt image has loaded, but this time, it's brought forward by <b>530ms</b> because it started loading <b>752ms</b> faster, and the document is fully loaded <b>562ms</b> faster, again because the external resources could all start loading faster.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Z05bcWVJtHoo9kkgl6IJj/941868fd08a160c81c61be2590b19107/image3-3.png" />
            
            </figure><p>The final four requests (highlighted in yellow) come back as 304 Not Modified responses using a <code>If-None-Match</code> header. By default, Cloudflare Pages requires the browser to confirm that all assets are fresh, and so, on the off chance that they were updated between the Early Hints response and when they come to being used, the browser is checking if they have changed. Since they haven't, there's no contentful body to download, and the response completes quickly. This can be avoided by setting a custom <code>Cache-Control</code> header on these assets using <a href="https://developers.cloudflare.com/pages/platform/headers/">a <code>_headers</code> file</a>. For example, you could cache these images for one minute with a rule like:</p>
            <pre><code># _headers

/*.png
  Cache-Control: max-age=60</code></pre>
            <p>We could take this performance audit further by exploring other features that Cloudflare offers, such as <a href="https://support.cloudflare.com/hc/en-us/articles/200168196">automatic CSS minification</a>, <a href="https://developers.cloudflare.com/images/">Cloudflare Images</a>, and <a href="https://developers.cloudflare.com/images/image-resizing/">Image Resizing</a>.</p><p>We already serve Cloudflare Pages from <a href="/cloudflare-pages-is-lightning-fast/">one of the fastest networks in the world</a> — Early Hints simply allows developers to take advantage of our global network even further.</p>
    <div>
      <h2>Using Early Hints and Cloudflare Pages</h2>
      <a href="#using-early-hints-and-cloudflare-pages">
        
      </a>
    </div>
    <p>The Early Hints feature on Cloudflare is currently restricted to caching <code>Link</code> headers in a webpage's response. Typically, this would mean that Cloudflare Pages users would either need to use the <code>_headers</code> file, or Pages Functions to apply these headers. However, for your convenience, we've also added support to transform any <code>&lt;link&gt;</code> HTML elements you include in your body into <code>Link</code> headers. This allows you to directly control the Early Hints you send, straight from the same document where you reference these resources – no need to come out of HTML to take advantage of Early Hints.</p><p>For example, for the following HTML document, will generate an Early Hints response:</p><p><b>HTML Document</b></p>
            <pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;link rel="preload" as="style" href="/styles.css" /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;!-- ... --&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
            <p><b>Early Hints Response</b></p>
            <pre><code>103 Early Hints
Link: &lt;/styles.css&gt;; rel=preload; as=style</code></pre>
            <p>As previously mentioned, <code>Link</code> headers can also be set with a <a href="/custom-headers-for-pages/"><code>_headers</code> file</a> if you prefer:</p>
            <pre><code># _headers

/
  Link: &lt;/styles.css&gt;; rel=preload; as=style</code></pre>
            <p>Early Hints (and the automatic HTML <code>&lt;link&gt;</code> parsing) has already been enabled automatically for all <code>pages.dev</code> domains. If you have any custom domains configured on your Pages project, make sure to enable Early Hints on that domain in the Cloudflare dashboard under the "Speed" tab. More information can be found in our <a href="https://developers.cloudflare.com/pages/platform/early-hints/">documentation</a>.</p><p>Additionally, in the future, we hope to support the Smart Early Hints features. Smart Early Hints will enable Cloudflare to automatically generate Early Hints, even when no <code>Link</code> header or <code>&lt;link&gt;</code> elements exist, by analyzing website traffic and inferring which resources are important for a given page. We'll be sharing more about Smart Early Hints soon.</p><p>In the meantime, try out <a href="https://developers.cloudflare.com/pages/platform/early-hints/">Early Hints on Pages</a> today! Let us know how much of a loading improvement you see in <a href="https://discord.com/invite/cloudflaredev">our Discord server</a>.</p>
    <div>
      <h2>Watch on Cloudflare TV</h2>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Early Hints]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Product News]]></category>
            <guid isPermaLink="false">3XJwgZh2bmW4PvjEU8BlCg</guid>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing Pages Plugins]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-plugins/</link>
            <pubDate>Thu, 12 May 2022 12:58:49 GMT</pubDate>
            <description><![CDATA[ Introducing Pages Plugins – reusable and customizable chunks of runtime code that can be incorporated anywhere within your Pages application. Try one of the officially supported Plugins from our partners or build your own ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Last November, we <a href="/cloudflare-pages-goes-full-stack/">announced</a> that Pages is now a full-stack development platform with our open beta integration with Cloudflare Workers. Using file-based routing, you can drop your Pages Functions into a <code>/functions</code> folder and deploy them alongside your static assets to add dynamic functionality to your site. However, throughout this beta period, we observed the types of projects users have been building, noticed some common patterns, and identified ways to make these users more efficient.</p><p>There are certain functionalities that are shared between projects; for example, validating authorization headers, creating an API server, reporting errors, and integrating with third-party vendors to track aspects like performance. The frequent need for these patterns across projects made us wonder, “What if we could provide the ready-made code for developers to add to their existing project?”</p><p>Introducing Pages Plugins!</p>
    <div>
      <h2>What’s a Pages Plugin?</h2>
      <a href="#whats-a-pages-plugin">
        
      </a>
    </div>
    <p>With <a href="/cloudflare-pages-goes-full-stack/">Pages Functions</a>, we introduced file-based routing, so users could avoid writing their own routing logic, significantly reducing the amount of boilerplate code a typical application requires. Pages Plugins aims to offer a similar experience!</p><p>A Pages Plugin is a reusable – and customizable – chunk of runtime code that can be incorporated anywhere within your Pages application. A Plugin is effectively a composable Pages Function, granting Plugins the full power of Functions (and therefore, Workers), including the ability to set up middleware, parameterized routes, and static assets.</p>
    <div>
      <h2>How does it work?</h2>
      <a href="#how-does-it-work">
        
      </a>
    </div>
    <p>Today, Pages Plugins is launching with a couple of ready-made solutions for Sentry, Honeycomb, and Stytch (more below), but it’s important to note that developers anywhere can create and share their Pages Plugins, too! You just need to install a Plugin, mount it to a route within the <code>/functions</code> directory, and configure the Plugin according to its needs.</p><p>Let’s take a look at a Plugins example for a hypothetical ACME logger:</p><p>Assume you find an <code>@acme/pages-plugin-logger</code> package on npm and want to use it within your application – you’d install, import, and invoke it as you would any other npm module. After passing through the required (hypothetical) configuration and mounting it as the top-level middleware’s <code>onRequest</code> export, the ACME logger will be reporting on all incoming requests:</p>
            <pre><code>// file: /functions/_middleware.ts

import MyLogger from "@acme/pages-plugin-logger";

// Setup logging for all URL routes &amp; methods
export const onRequest = MyLogger({
 endpoint: "https://logs.acme.com/new",
 secret: "password",
});</code></pre>
            <p>You can help grow the Plugins ecosystem by building and sharing your Plugins on <a href="https://www.npmjs.com/">npm</a> and our <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/community-plugins/">developer documentation</a>, and you can immediately get started by using one of Cloudflare’s official launch partner Plugins today.</p>
    <div>
      <h2>Introducing our Plugins launch partners</h2>
      <a href="#introducing-our-plugins-launch-partners">
        
      </a>
    </div>
    <p>With Pages, we’re always working to see how we can best cater to user workflows by integrating directly with users’ preferred tools. We see Plugins as an excellent opportunity to collaborate with popular third-party observability, monitoring, and authentication providers to provide their own Pages Plugins.</p><p>Today, we’re proud to launch our Pages Plugins with <a href="https://sentry.io/welcome/">Sentry</a>, <a href="https://www.honeycomb.io/">Honeycomb</a> and <a href="https://stytch.com/">Stytch</a> as official partners!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UfnNcBSdnluYtxgQIpI4v/943ae59eecd5d8705836d705ae2ceaf7/image2-22.png" />
            
            </figure>
    <div>
      <h3><a href="https://sentry.io/welcome/">Sentry</a></h3>
      <a href="#">
        
      </a>
    </div>
    <p><a href="http://sentry.io/">Sentry</a> provides developer-first application monitoring for real-time insights into your production deployments. With Sentry you can see the errors, crashes, or latencies experienced while using your app and get the deep context needed to solve issues quickly, like the line of code where the error occurred, the developer or commit that introduced the error, or the API call or database query causing the slowdown. The <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/sentry">Sentry Plugin</a> automatically captures any exceptions in your Pages Functions and sends them to Sentry where you can aggregate, analyze, and triage any issues your application encounters.</p>
            <pre><code>// ./functions/_middleware.ts

import sentryPlugin from "@cloudflare/pages-plugin-sentry";

export const onRequest = sentryPlugin({
 dsn: "YOUR_SENTRY_DSN",
});</code></pre>
            
    <div>
      <h3><a href="https://www.honeycomb.io/">Honeycomb</a></h3>
      <a href="#">
        
      </a>
    </div>
    <p>Similarly, Honeycomb is also an observability and monitoring platform meant to visualize, analyze and improve application quality and performance to help you find patterns and outliers in your application data. The <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/honeycomb">Honeycomb Plugin</a> creates traces for every request that your Pages application receives and automatically sends that information to Honeycomb for analysis.</p>
            <pre><code>// ./functions/_middleware.ts

import honeycombPlugin from "@cloudflare/pages-plugin-honeycomb";

export const onRequest = honeycombPlugin({
 apiKey: "YOUR_HONEYCOMB_API_KEY",
 dataset: "YOUR_HONEYCOMB_DATASET_NAME",
});</code></pre>
            
    <div>
      <h3><a href="https://stytch.com/?utm_source=cloudflare&amp;utm_medium=blog">Stytch</a></h3>
      <a href="#">
        
      </a>
    </div>
    <p>Observability is just one use case of how Pages Plugins can help you build a more powerful app. Stytch is an API-first platform that improves security and promotes a better user experience with <a href="https://www.cloudflare.com/learning/security/threats/what-is-passwordless-authentication/">passwordless authentication</a>. Our <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/stytch">Stytch Plugin</a> transparently validates user sessions, allowing you to easily protect parts of your application behind a Stytch login.</p>
            <pre><code>// ./functions/_middleware.ts

import stytchPlugin from "@cloudflare/pages-plugin-stytch";
import { envs } from "@cloudflare/pages-plugin-stytch/api";

export const onRequest = stytchPlugin({
  project_id: "YOUR_STYTCH_PROJECT_ID",
  secret: "YOUR_STYTCH_PROJECT_SECRET",
  env: envs.live
});</code></pre>
            
    <div>
      <h2>More Plugins, more fun!</h2>
      <a href="#more-plugins-more-fun">
        
      </a>
    </div>
    <p>As a developer platform, it’s crucial to build relationships with the creators of the tooling and frameworks you use alongside Pages, and we look forward to growing our partnership ecosystem even more in the future. However, beyond partnerships, we realize there are some more extremely useful Plugins that we built out to get you started!</p><ul><li><p><b>Google Chat:</b> creates a Google Chat bot which can respond to messages. It also includes an API for interacting with Google Chat (for example, for creating messages) without the need for user input. This API is useful for situations such as alerts.</p></li><li><p><b>Cloudflare Access:</b> a middleware to validate Cloudflare Access JWT assertions. It also includes an API to lookup additional information about a given user's JSON Web Token.</p></li><li><p><b>Static forms</b>: intercepts static HTML form submissions and can perform actions such as storing the data in KV.</p></li><li><p><b>GraphQL</b>: creates a GraphQL API for a given schema. It also ships with <a href="https://github.com/graphql/graphql-playground">the GraphQL Playground</a> to simplify development and help you test out your API.</p></li></ul><p>Over the next couple of months we will be working to build out some of the most requested Plugins relevant to your projects. For now, you can find all officially supported Plugins in our <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/">developer documentation</a>.</p>
    <div>
      <h2>No time to wait? Author your own!</h2>
      <a href="#no-time-to-wait-author-your-own">
        
      </a>
    </div>
    <p>But don’t let us be your bottleneck! The beauty of Plugins is how easy they are to create and distribute. In fact, we <b>encourage</b> you to try out our <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/">documentation</a> in order to create and share your own Plugin because chances are if you’re building a Plugin for your own project, there is someone else who would benefit greatly from it too!</p><p>We're excited to see Plugins from the community solving their own common use-cases or as integrations with their favorite platforms. Once you’ve built a Plugin, you can surface your work if you choose by creating a PR against <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/community-plugins/">the Community Plugins page in our documentation</a>. This way any Pages user can read about your Plugin and mount it in their own Pages application.</p>
    <div>
      <h2>What’s next for Pages Functions</h2>
      <a href="#whats-next-for-pages-functions">
        
      </a>
    </div>
    <p>As you try out Plugins and take advantage of our Functions offering, it’s important to note there are some truly exciting updates coming soon. As we march toward the Functions general availability launch, we will provide proper analytics and logging, so you can have better insight into your site’s performance and visibility into issues for debugging. Additionally, with R2 now in open beta, and <a href="https://www.cloudflare.com/developer-platform/products/d1/">D1</a> in the works, we’re excited to provide support for R2 and D1 bindings for your full stack Pages projects soon!</p><p>Of course, because Functions is still in open beta, we currently offer 100k requests per day for free, however, as we aim for general availability of Functions, you can expect a billing model similar to the <a href="https://developers.cloudflare.com/workers/platform/pricing/">Workers Paid</a> billing model.</p>
    <div>
      <h2>Share what you build</h2>
      <a href="#share-what-you-build">
        
      </a>
    </div>
    <p>While you begin building out your Plugin, be sure to reach out to us in our <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord server</a> in the #pages-plugins channel. We’d love to see what you’re building and help you along the way!</p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <guid isPermaLink="false">sT8hM1mh7oDHKdzzd3F4R</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing Direct Uploads for Cloudflare Pages]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-direct-uploads/</link>
            <pubDate>Tue, 10 May 2022 13:01:06 GMT</pubDate>
            <description><![CDATA[ Pages now supports direct uploads to give you more power to build and iterate how you want and with the tools you want ]]></description>
            <content:encoded><![CDATA[ <p></p><p>With Pages, we are constantly looking for ways to improve the developer experience. One of the areas we are keen to focus on is removing any barriers to entry for our users regardless of their use case or existing set up. Pages is an all-in-one solution with an automated Continuous Integration (CI) pipeline to help you build and deploy your site with one commit to your projects’ repositories hosted on GitHub or GitLab.</p><p>However, we realize that this excluded repositories that used a source control provider that Pages didn’t yet support and required varying build complexities. Even though Pages continues to build first-class integrations – for example, we <a href="/cloudflare-pages-partners-with-gitlab/">added GitLab support</a> in November 2021 – there are numerous providers to choose from, some of which use `git` alternatives like <a href="https://subversion.apache.org/">SVN</a> or <a href="https://www.mercurial-scm.org/">Mercurial</a> for their version control systems. It’s also common for larger companies to self-host their project repositories, guarded by a mix of custom authentication and/or proxy protocols.</p><p>Pages needed a solution that worked regardless of the repository’s source location and accommodate build project’s complexity. Today, we’re thrilled to announce that Pages now supports direct uploads to give you more power to build and iterate how you want and with the tools you want.</p>
    <div>
      <h2>What are direct uploads?</h2>
      <a href="#what-are-direct-uploads">
        
      </a>
    </div>
    <p>Direct uploads enable you to push your build artifacts directly to Pages, side-stepping the automatic, done-for-you CI pipeline that Pages provides for GitHub and GitLab repositories. This means that connecting a Pages project to a git repository is optional. In fact, using git or any version control system is optional!</p><p>Today, you can bring your assets directly to Pages by dragging and dropping them into our dashboard or pushing them through Wrangler CLI. You also have the power to use your own CI tool whether that’s something like <a href="http://developers.cloudflare.com/pages/how-to/use-direct-upload-with-continuous-integration/">GitHub Actions or CircleCI</a> to handle your build. Taking your output directory you can bring these files directly to Pages to create a new project and all subsequent deployments after that. Every deployment will be distributed right to the Cloudflare network within seconds.</p>
    <div>
      <h2>How does it work?</h2>
      <a href="#how-does-it-work">
        
      </a>
    </div>
    <p>After using your preferred CI tooling outside of Pages, there are two ways to bring your pre-built assets and create a project with the direct uploads feature:</p><ol><li><p>Use the Wrangler CLI</p></li><li><p>Drag and drop them into the Pages interface</p></li></ol>
    <div>
      <h3>Wrangler CLI</h3>
      <a href="#wrangler-cli">
        
      </a>
    </div>
    <p>With an estimated 43k weekly Wrangler downloads, you too can use it to iterate quickly on your Pages projects right through the command line. With Wrangler (now with brand-new <a href="/10-things-I-love-about-wrangler">updates</a>!), you can both create your project and new deployments with a single command.</p><p>After Wrangler is installed and authenticated with your Cloudflare account, you can execute the following command to get your site up and running:</p>
            <pre><code>npx wrangler pages publish &lt;directory&gt;</code></pre>
            <div></div>
<p></p><p>Integration with Wrangler provides not only a great way to publish changes in a fast and consecutive manner, but also enables a seamless workflow between CI tooling for building right to Pages for deployment. Check out our tutorials on using <a href="http://developers.cloudflare.com/pages/how-to/use-direct-upload-with-continuous-integration/">CircleCI and GitHub Actions</a> with Pages!</p>
    <div>
      <h3>Drag and drop</h3>
      <a href="#drag-and-drop">
        
      </a>
    </div>
    <p>However, we realize that sometimes you just want to get your site deployed instantaneously without any additional set up or installations. In fact, getting started with Pages shouldn’t have to require extensive configuration. The drag and drop feature allows you to take your pre-built assets and virtually drag them onto the Pages UI. With either a zip file or a single folder of assets, you can watch your project deploy in just a few short seconds straight to the 270+ cities in our network.</p><div></div>
<p></p>
    <div>
      <h2>What can you build?</h2>
      <a href="#what-can-you-build">
        
      </a>
    </div>
    <p>With this ease of deploying projects, the possibilities of what you can build are still endless. You can enjoy the fruits of Pages in a project created with direct uploads including but not limited to unique preview URLs, integration with Workers, Access and Web Analytics, and custom redirects/headers.</p><p>In thinking about your developer setup, direct uploads provide the flexibility to build the way you want such as:</p><ul><li><p>Designing and building your own CI workflow</p></li><li><p>Utilizing the CI tooling of your choice</p></li><li><p>Accommodating complex monorepo structures</p></li><li><p>Implementing custom CI logic for your builds.</p></li></ul>
    <div>
      <h2>Migrating from Workers Sites</h2>
      <a href="#migrating-from-workers-sites">
        
      </a>
    </div>
    <p>We’ll have to admit, the idea of publishing assets directly to our network came from a sister product to Pages called <a href="/workers-sites/">Workers Sites</a> and the resemblance is striking! However, Pages affords many feature enhancements to the developer experience that show as a pain point on Workers Sites.</p><p>With Pages direct uploads, you can enjoy the freedom and flexibility of customizing your workflow that Workers Sites provides while including an interface to track and share changes and manage production/preview environments. <a href="https://developers.cloudflare.com/pages/migrations/migrating-from-workers/">Check out our tutorial</a> on how to migrate over from Workers Sites.</p><p>This release immediately unlocks a broad range of use cases, allowing the most basic of projects to the most advanced to start deploying their websites to Pages today. Refer to our <a href="https://developers.cloudflare.com/pages/platform/direct-upload/">developer documentation</a> for more technical details. As always, head over to the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a> server and let us know what you think in the #direct-uploads-beta channel.</p>
    <div>
      <h2>Join us at Cloudflare Connect!</h2>
      <a href="#join-us-at-cloudflare-connect">
        
      </a>
    </div>
    <p>Calling all New York City developers! If you’re interested in learning more about Cloudflare Pages, join us for a series of workshops on how to build a full stack application on Thursday, May 12th. Follow along with demonstrations of using Pages alongside other products like Workers, Images and Cloudflare Gateway, and hear directly from our product managers. <a href="https://events.www.cloudflare.com/flow/cloudflare/connect2022nyc/landing/page/page">Register now</a>!</p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">54zX3KuZvT6IeXghtXaDt6</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Greg Brimble</dc:creator>
            <dc:creator>John Fawcett</dc:creator>
            <dc:creator>Sid Chatterjee</dc:creator>
        </item>
        <item>
            <title><![CDATA[Supporting Remix with full stack Cloudflare Pages]]></title>
            <link>https://blog.cloudflare.com/remix-on-cloudflare-pages/</link>
            <pubDate>Fri, 17 Dec 2021 20:40:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare Pages now natively supports full stack Remix applications ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4L8XNQXMAMjKwMWhI8FceZ/c893e90edadc4590e7229aebe4d5c447/remix-1.png" />
            
            </figure><p>We announced the <a href="/cloudflare-pages-goes-full-stack/">open beta of full stack Cloudflare Pages</a> in November and have since seen widespread uptake from developers looking to add dynamic functionality to their applications. Today, we're excited to announce Pages' support for Remix applications, powered by our full stack platform.</p>
    <div>
      <h3>The new kid on the block: Remix</h3>
      <a href="#the-new-kid-on-the-block-remix">
        
      </a>
    </div>
    <p><a href="https://remix.run/">Remix</a> is a new framework that is focused on fully utilizing the power of the web. Like Cloudflare Workers, it uses modern JavaScript APIs, and it places emphasis on web fundamentals such as meaningful HTTP status codes, caching and optimizing for both usability and performance. One of the biggest features of Remix is its transportability: Remix provides a platform-agnostic interface and adapters allowing it to be deployed to a growing number of providers. Cloudflare Workers was available at Remix's launch, but what makes Workers different in this case, is the native compatibility that Workers can offer.</p><blockquote><p><i>One of the main inspirations for Remix was the way Cloudflare Workers uses native web APIs for handling HTTP requests and responses. It's a brilliant decision because developers are able to reuse knowledge on the server that they gained building apps in the browser! Remix runs natively on Cloudflare Workers, and the results we've seen so far are fantastic. We are incredibly excited about the potential that Cloudflare Workers and Pages unlocks for building apps that run at the edge!</i>- <b>Michael Jackson</b>, CEO at <a href="https://remix.run/">Remix</a></p></blockquote><p>This native compatibility means that as you learn how to write applications in Remix, you're also learning how to write Cloudflare Workers (and vice versa). But it also means better performance! Rather than having a Node.js process running on a server — which could be far away from your users, could be overwhelmed in the case of high traffic, and has to map between Node.js' runtime and the modern Fetch API — you can deploy to Cloudflare's network and requests will be routed to any one of our 250+ locations. This means better performance for your users, with <a href="/250-cities-is-just-the-start/">95% of the entire Internet-connected world lying within 50ms of a Cloudflare presence, and 80% of the Internet-connected world within 20ms</a>.</p>
    <div>
      <h3>Integrating with Cloudflare</h3>
      <a href="#integrating-with-cloudflare">
        
      </a>
    </div>
    <p>More often than not, full stack applications need some place to store data. Cloudflare offers three all-encompassing options here:</p><ul><li><p>KV, our high performance and globally replicated key-value datastore.</p></li><li><p>Durable Objects, our strongly consistent coordination primitive which can be restricted to a given jurisdiction.</p></li><li><p><a href="https://www.cloudflare.com/developer-platform/products/r2/">R2</a> (coming soon!), our fast and reliable <a href="https://www.cloudflare.com/learning/cloud/what-is-object-storage/">object storage</a>.</p></li></ul><p>Remix already tightly integrates with <a href="https://remix.run/docs/en/v1/api/remix#createcloudflarekvsessionstorage-cloudflare-workers">KV for session storage</a>, and a Durable Objects integration is in progress. Additionally, Cloudflare's other features, such as <a href="https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties">geolocating incoming requests</a>, <a href="https://developers.cloudflare.com/workers/runtime-apis/html-rewriter">HTMLRewriter</a> and our <a href="https://developers.cloudflare.com/workers/runtime-apis/cache">Cache API</a>, are all available from within your Remix application.</p>
    <div>
      <h3>Deploying to Cloudflare Pages</h3>
      <a href="#deploying-to-cloudflare-pages">
        
      </a>
    </div>
    <p>Cloudflare Pages was already capable of serving static assets from the Cloudflare edge, but now with November's release of serverless functions powered by Cloudflare Workers, it has evolved into an entire platform perfectly suited for <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">hosting full stack applications</a>.</p><p>To get started with Remix and Cloudflare Pages today, run the following in your terminal, and select "Cloudflare Pages" when asked "Where do you want to deploy?":</p>
            <pre><code>npx create-remix@latest</code></pre>
            <p>Then create a repository on <a href="https://developers.cloudflare.com/pages/platform/github-integration">GitHub</a> or <a href="/cloudflare-pages-partners-with-gitlab/">GitLab</a>, <code>git commit</code>, and <code>git push</code> the newly created folder. Finally, navigate to Cloudflare Pages, select your repository, and select "Remix" from the dropdown of framework presets. Your new application will be available on your <code>pages.dev</code> subdomain, or you can <a href="https://developers.cloudflare.com/pages/get-started#adding-a-custom-domain">connect it to any of your custom domains</a>.</p><p>Your folder will have a <code>functions/[[path]].ts</code> file. This is <a href="https://developers.cloudflare.com/pages/platform/functions">the functions integration</a> where we serve your Remix application on all paths of your website. <a href="https://remix.run/docs/en/v1/api/conventions#file-name-conventions">The <code>app</code> folder</a> is where the bulk of your Remix application's logic is. With Pages' support for <a href="https://developers.cloudflare.com/pages/platform/rollbacks">rollbacks</a> and <a href="https://developers.cloudflare.com/pages/platform/preview-deployments">preview deployments</a>, you can safely test any changes to your application, and, with <a href="/wrangler-v2-beta">the wrangler 2.0 beta</a>, testing locally is just a simple case of <code>npm run dev</code>.</p>
    <div>
      <h3>The future of frameworks on Cloudflare Pages</h3>
      <a href="#the-future-of-frameworks-on-cloudflare-pages">
        
      </a>
    </div>
    <p>Remix is the second framework to integrate natively with full stack Cloudflare Pages, following <a href="https://kit.svelte.dev/">SvelteKit</a>, which was available at launch. But this is just the beginning! We have a lot more in store for our integration with Remix and other frameworks. Stay tuned for improvements on  Pages’ build times and other areas of the developer experience, as well as new features to the platform.</p>
    <div>
      <h3>Join our community!</h3>
      <a href="#join-our-community">
        
      </a>
    </div>
    <p>If you are new to the Cloudflare Pages and Workers world, <a href="https://discord.com/invite/cloudflaredev">join our Discord server</a> and show us what you’re building. Whether it’s a new full stack application on Remix or even a simple static site, we’d love to hear from you.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Full Stack]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">38eHIbplcXpnQ4Llvb0JEK</guid>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
        <item>
            <title><![CDATA[Building a full stack application with Cloudflare Pages]]></title>
            <link>https://blog.cloudflare.com/building-full-stack-with-pages/</link>
            <pubDate>Wed, 17 Nov 2021 13:58:53 GMT</pubDate>
            <description><![CDATA[ Full-stack support for Cloudflare Pages is now in open beta, and you can test it today with this example image-sharing project that integrates with KV, Durable Objects, Cloudflare Images and Cloudflare Access.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>We were so excited to <a href="/cloudflare-pages-goes-full-stack">announce support for full stack applications in Cloudflare Pages</a> that we knew we had to show it off in a big way. We've built a sample image-sharing platform to demonstrate how you can add serverless functions right from within Pages with help from Cloudflare Workers. With just one new file to your project, you can add dynamic rendering, interact with other APIs, and persist data with KV and Durable Objects. The possibilities for full-stack applications, in combination with Pages' quick development cycles and unlimited preview environments, gives you the power to create almost any application.</p><p>Today, we're walking through our example image-sharing platform. We want to be able to share pictures with friends while still also keeping some images private. We'll build a JSON API with Functions (storing data on KV and Durable Objects), integrate with Cloudflare Images and Cloudflare Access, and use React for our front end.</p><p>If you're wanting to dive right into the good stuff, <a href="https://images.pages.dev/">our demo instance is published here</a>, and <a href="https://github.com/cloudflare/images.pages.dev">the code is on GitHub</a>, but stick around for a more gentle approach.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6ONc6WtXvEqXxJXIVlwX4o/85109aa1b16e6a79fc0b1ed60eccf485/image2-17.png" />
            
            </figure>
    <div>
      <h2>Building serverless functions with Cloudflare Pages</h2>
      <a href="#building-serverless-functions-with-cloudflare-pages">
        
      </a>
    </div>
    
    <div>
      <h3>File-based routing</h3>
      <a href="#file-based-routing">
        
      </a>
    </div>
    <p>If you're not already familiar, Cloudflare Pages <a href="https://developers.cloudflare.com/pages/get-started">connects with your git provider</a> (GitHub and <a href="/cloudflare-pages-partners-with-gitlab">GitLab</a>), and automates the deployment of your static site to Cloudflare's network. Functions lets you enhance these apps by sprinkling in dynamic data. If you haven't already, <a href="https://dash.cloudflare.com/sign-up/pages">you can sign up here</a>.</p><p>In our project, let's create a new function:</p>
            <pre><code>// ./functions/time.js


export const onRequest = () =&gt; {
  return new Response(new Date().toISOString())
}</code></pre>
            <p><code>git commit</code>-ing and pushing this file should trigger a build and deployment of your first Pages function. Any requests for <code>/time</code> will be served by this function, and all other requests will fall-back to the static assets of your project. Placing Functions files in directories works as you'd expect: <code>./functions/api/time.js</code> would be available at <code>/api/time</code> and <code>./functions/some_directory/index.js</code> would be available at <code>/some_directory</code>.</p><p>We also support TypeScript (<code>./functions/time.ts</code> would work just the same), as well as parameterized files:</p><ul><li><p><code>./functions/todos/[id].js</code> with single square brackets will match all requests like <code>/todos/123</code>;</p></li><li><p>and <code>./functions/todos/[[path]].js</code> with double square brackets, will match requests for any number of path segments (e.g. <code>/todos/123/subtasks</code>).</p></li></ul><p>We declare a <code>PagesFunction</code> type in the <a href="https://github.com/cloudflare/workers-types">@cloudflare/workers-types</a> library which you can use to type-check your Functions.</p>
    <div>
      <h3>Dynamic data</h3>
      <a href="#dynamic-data">
        
      </a>
    </div>
    <p>So, returning to our image-sharing app, let's assume we already have some images uploaded, and we want to display them on the homepage. We'll need an endpoint which will return a list of these images, which the front-end can call:</p>
            <pre><code>// ./functions/api/images.ts

export const jsonResponse = (value: any, init: ResponseInit = {}) =&gt;
  new Response(JSON.stringify(value), {
    headers: { "Content-Type": "application/json", ...init.headers },
    ...init,
  });

const generatePreviewURL = ({
  previewURLBase,
  imagesKey,
  isPrivate,
}: {
  previewURLBase: string;
  imagesKey: string;
  isPrivate: boolean;
}) =&gt; {
  // If isPrivate, generates a signed URL for the 'preview' variant
  // Else, returns the 'blurred' variant URL which never requires signed URLs
  // https://developers.cloudflare.com/images/cloudflare-images/serve-images/serve-private-images-using-signed-url-tokens

  return "SIGNED_URL";
};

export const onRequestGet: PagesFunction&lt;{
  IMAGES: KVNamespace;
}&gt; = async ({ env }) =&gt; {
  const { imagesKey } = (await env.IMAGES.get("setup", "json")) as Setup;

  const kvImagesList = await env.IMAGES.list&lt;ImageMetadata&gt;({
    prefix: `image:uploaded:`,
  });

  const images = kvImagesList.keys
    .map((kvImage) =&gt; {
      try {
        const { id, previewURLBase, name, alt, uploaded, isPrivate } =
          kvImage.metadata as ImageMetadata;

        const previewURL = generatePreviewURL({
          previewURLBase,
          imagesKey,
          isPrivate,
        });

        return {
          id,
          previewURL,
          name,
          alt,
          uploaded,
          isPrivate,
        };
      } catch {
        return undefined;
      }
    })
    .filter((image) =&gt; image !== undefined);

  return jsonResponse({ images });
};</code></pre>
            <p>Eagle-eyed readers will notice we're exporting <code>onRequestGet</code> which lets us only respond to <code>GET</code> requests.</p><p>We're also using a KV namespace (accessed with <code>env.IMAGES</code>) to store information about images that have been uploaded. To create a binding in your Pages project, navigate to the "Settings" tab.</p><p>![](<a href="/content/images/2021/11/unnamed-15.png_REGULAR">http://staging.blog.mrk.cfdata.org/content/images/2021/11/unnamed-15.png_REGULAR</a> "Screenshot of the "Functions" page on the Pages project "Settings" tab in the Cloudflare dashboard")</p>
    <div>
      <h3>Interfacing with other APIs</h3>
      <a href="#interfacing-with-other-apis">
        
      </a>
    </div>
    <p>Cloudflare Images is an inexpensive, high-performance, and featureful service for <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">hosting</a> and transforming images. You can create multiple variants to render your images in different ways and control access with signed URLs. We'll add a function to interface with this service's API and upload incoming files to Cloudflare Images:</p>
            <pre><code>// ./functions/api/admin/upload.ts

export const onRequestPost: PagesFunction&lt;{
  IMAGES: KVNamespace;
}&gt; = async ({ request, env }) =&gt; {
  const { apiToken, accountId } = (await env.IMAGES.get(
    "setup",
    "json"
  )) as Setup;

  // Prepare the Cloudflare Images API request body
  const formData = await request.formData();
  formData.set("requireSignedURLs", "true");
  const alt = formData.get("alt") as string;
  formData.delete("alt");
  const isPrivate = formData.get("isPrivate") === "on";
  formData.delete("isPrivate");

  // Upload the image to Cloudflare Images
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/accounts/${accountId}/images/v1`,
    {
      method: "POST",
      body: formData,
      headers: {
        Authorization: `Bearer ${apiToken}`,
      },
    }
  );

  // Store the image metadata in KV
  const {
    result: {
      id,
      filename: name,
      uploaded,
      variants: [url],
    },
  } = await response.json&lt;{
    result: {
      id: string;
      filename: string;
      uploaded: string;
      requireSignedURLs: boolean;
      variants: string[];
    };
  }&gt;();

  const metadata: ImageMetadata = {
    id,
    previewURLBase: url.split("/").slice(0, -1).join("/"),
    name,
    alt,
    uploaded,
    isPrivate,
  };

  await env.IMAGES.put(
    `image:uploaded:${uploaded}`,
    "Values stored in metadata.",
    { metadata }
  );
  await env.IMAGES.put(`image:${id}`, JSON.stringify(metadata));

  return jsonResponse(true);
};</code></pre>
            
    <div>
      <h3>Persisting data</h3>
      <a href="#persisting-data">
        
      </a>
    </div>
    <p>We're already using KV to store information that is read often but rarely written to. What about features that require a bit more synchronicity?</p><p>Let's add a download counter to each of our images. We can create a <code>highres</code> variant in Cloudflare Images, and increment the counter every time a user requests a link. This requires a bit more setup, but unlocking the power of Durable Objects in your projects is absolutely worth it.</p><p>We'll need to create and publish the Durable Object class capable of maintaining this download count:</p>
            <pre><code>// ./durable_objects/downloadCounter.js
ts#example---counter

export class DownloadCounter {
  constructor(state) {
    this.state = state;
    // `blockConcurrencyWhile()` ensures no requests are delivered until initialization completes.
    this.state.blockConcurrencyWhile(async () =&gt; {
      let stored = await this.state.storage.get("value");
      this.value = stored || 0;
    });
  }

  async fetch(request) {
    const url = new URL(request.url);
    let currentValue = this.value;

    if (url.pathname === "/increment") {
      currentValue = ++this.value;
      await this.state.storage.put("value", currentValue);
    }

    return jsonResponse(currentValue);
  }
}</code></pre>
            
    <div>
      <h3>Middleware</h3>
      <a href="#middleware">
        
      </a>
    </div>
    <p>If you need to execute some code (such as authentication or logging) before you run your function, Pages offers easy-to-use middleware which can be applied at any level in your file-based routing. By creating a <code>_middleware.ts</code> file in a directory, we know to first run this file, and then execute your function when <code>next()</code> is called.</p><p>In our application, we want to prevent unauthorized users from uploading images (<code>/api/admin/upload</code>) or deleting images (<code>/api/admin/delete</code>). Cloudflare Access lets us apply <a href="https://www.cloudflare.com/learning/access-management/role-based-access-control-rbac/">role-based access control</a> to all or part of our application, and you only need a single file to integrate it into our serverless functions. We create  <code>./functions/api/admin/_middleware.ts</code> which will apply to all incoming requests at <code>/api/admin/*</code>:</p>
            <pre><code>// ./functions/api/admin/_middleware.ts

const validateJWT = async (jwtAssertion: string | null, aud: string) =&gt; {
  // If the JWT is valid, return the JWT payload
  // Else, return false
  // https://developers.cloudflare.com/cloudflare-one/identity/users/validating-json

  return jwtPayload;
};

const cloudflareAccessMiddleware: PagesFunction&lt;{ IMAGES: KVNamespace }&gt; =
  async ({ request, env, next, data }) =&gt; {
    const { aud } = (await env.IMAGES.get("setup", "json")) as Setup;

    const jwtPayload = await validateJWT(
      request.headers.get("CF-Access-JWT-Assertion"),
      aud
    );

    if (jwtPayload === false)
      return new Response("Access denied.", { status: 403 });

    // We could also use the data object to pass information between middlewares
    data.user = jwtPayload.email;

    return await next();
  };

export const onRequest = [cloudflareAccessMiddleware];</code></pre>
            <p>Middleware is a powerful tool at your disposal allowing you to easily protect parts of your application with Cloudflare Access, or quickly integrate with <a href="https://www.cloudflare.com/learning/performance/what-is-observability/">observability</a> and error logging platforms such as Honeycomb and Sentry.</p>
    <div>
      <h2>Integrating as Jamstack</h2>
      <a href="#integrating-as-jamstack">
        
      </a>
    </div>
    <p>The "Jam" of "Jamstack" stands for JavaScript, API and Markup. Cloudflare Pages previously provided the 'J' and 'M', and with Workers in the middle, you can truly go full-stack Jamstack.</p><p>We've built the front end of this image sharing platform with <a href="https://create-react-app.dev/">Create React App</a> as an approachable example, but <a href="https://developers.cloudflare.com/pages/platform/build-configuration#framework-presets">Cloudflare Pages natively integrates with an ever-growing number of frameworks</a> (currently 23), and you can always <a href="https://developers.cloudflare.com/pages/platform/build-configuration#build-commands-and-directories">configure your own entirely custom build command</a>.</p><p>Your front end simply needs to make a call to the Functions we've already configured, and render out that data. We're using <a href="https://swr.vercel.app/">SWR</a> to simplify things, but you could do this with entirely vanilla JavaScript <code>fetch</code>-es, if that's your preference.</p>
            <pre><code>// ./src/components/ImageGrid.tsx

export const ImageGrid = () =&gt; {
  const { data, error } = useSWR&lt;{ images: Image[] }&gt;("/api/images");

  if (error || data === undefined) {
    return &lt;div&gt;An unexpected error has occurred when fetching the list of images. Please try again.&lt;/div&gt;;
  }


  return (
    &lt;div&gt;
      {data.images.map((image) =&gt; (
        &lt;ImageCard image={image} key={image.id} /&gt;
      ))}
    &lt;/div&gt;
  );

}</code></pre>
            
    <div>
      <h2>Local development</h2>
      <a href="#local-development">
        
      </a>
    </div>
    <p>No matter how fast it is, iterating on a project like this can be painful if you have to push up every change in order to test how it works. We've released a first-class integration with wrangler for local development of Pages projects, including full support for Functions, Workers, secrets, environment variables and KV. Durable Objects support is coming soon.</p><p>Install from npm:</p>
            <pre><code>npm install wrangler@beta</code></pre>
            <p>and either serve a folder of static assets, or proxy your existing tooling:</p>
            <pre><code># Serve a directory
npx wrangler pages dev ./public

# or integrate with your other tools
npx wrangler pages dev -- npx react-scripts start</code></pre>
            
    <div>
      <h2>Go forth, and build!</h2>
      <a href="#go-forth-and-build">
        
      </a>
    </div>
    <p>If you like puppies, <a href="https://images.pages.dev/">we've deployed our image-sharing application here</a>, and if you like code, <a href="https://github.com/cloudflare/images.pages.dev">that's over on GitHub</a>. Feel free to fork and deploy it yourself! There's a five-minute setup wizard, and you'll need Cloudflare Images, Access, Workers, and Durable Objects.</p><p>We are so excited about the future of the Pages platform, and we want to hear what you're building! Show off your full-stack applications in the <a href="https://discord.com/channels/595317990191398933/783765338692386886">#what-i-built channel</a>, or get assistance in the <a href="https://discord.com/channels/595317990191398933/789155108529111069">#pages-help channel</a> on <a href="https://discord.gg/cloudflaredev">our Discord server</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3FMhGC7kxjUEspTnvUGjeQ/50a9a9bd201ed390f1f62c72bc9e2cb4/image1-37.png" />
            
            </figure>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Full Stack]]></category>
            <category><![CDATA[Cloudflare Images]]></category>
            <category><![CDATA[Cloudflare Access]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">48ToA8dVaTtXmVL58V9bJm</guid>
            <dc:creator>Greg Brimble</dc:creator>
            <dc:creator>Obinna Ekwuno</dc:creator>
        </item>
        <item>
            <title><![CDATA[Custom Headers for Cloudflare Pages]]></title>
            <link>https://blog.cloudflare.com/custom-headers-for-pages/</link>
            <pubDate>Wed, 27 Oct 2021 13:00:15 GMT</pubDate>
            <description><![CDATA[ We're excited to announce that Pages now natively supports custom headers on your projects! Simply create a _headers file in the build directory of your project and within it, define the rules you want to apply. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Until today, Cloudflare Workers has been a great solution to setting headers, but we wanted to create an even smoother developer experience. Today, we're excited to announce that Pages now natively supports custom headers on your projects! Simply create a <code>_headers</code> file in the build directory of your project and within it, define the rules you want to apply.</p>
            <pre><code>/developer-docs/*
  X-Hiring: Looking for a job? We're hiring engineers
(https://www.cloudflare.com/careers/jobs)</code></pre>
            
    <div>
      <h2>What can you set with custom headers?</h2>
      <a href="#what-can-you-set-with-custom-headers">
        
      </a>
    </div>
    <p>Being able to set custom headers is useful for a variety of reasons — let’s explore some of your most popular use cases.</p>
    <div>
      <h3>Search Engine Optimization (SEO)</h3>
      <a href="#search-engine-optimization-seo">
        
      </a>
    </div>
    <p>When you create a Pages project, a <code>pages.dev</code> deployment is created for your project which enables you to <a href="https://developers.cloudflare.com/pages/get-started">get started immediately</a> and easily <a href="https://developers.cloudflare.com/pages/platform/preview-deployments">preview changes</a> as you iterate. However, we realize this poses an issue — publishing multiple copies of your website can harm your rankings in search engine results. One way to solve this is by disabling indexing on all <code>pages.dev</code> subdomains, but we see many using their <code>pages.dev</code> subdomain as their primary domain. With today’s announcement you can attach headers such as <a href="https://developers.google.com/search/docs/advanced/robots/robots_meta_tag#xrobotstag"><code>X-Robots-Tag</code></a> to hint to Google and other search engines how you'd like your deployment to be indexed.</p><p>For example, to prevent your <code>pages.dev</code> deployment from being indexed, you can add the following to your <code>_headers</code> file:</p>
            <pre><code>https://:project.pages.dev/*
  X-Robots-Tag: noindex</code></pre>
            
    <div>
      <h3>Security</h3>
      <a href="#security">
        
      </a>
    </div>
    <p>Customizing headers doesn’t just help with your site’s search result ranking — a number of browser security features can be configured with headers. A few headers that can enhance your site’s security are:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options"><code><b>X-Frame-Options</b></code></a>: You can prevent <a href="https://owasp.org/www-community/attacks/Clickjacking">click-jacking</a> by informing browsers not to embed your application inside another (e.g. with an <code>&lt;iframe&gt;</code>).</p></li><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options"><code><b>X-Content-Type-Option: nosniff</b></code></a><b>:</b> To prevent browsers from interpreting a response as any other content-type than what is defined with the <code>Content-Type</code> header.</p></li><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy"><code><b>Referrer-Policy</b></code></a>: This allows you to customize how much information visitors give about where they're coming from when they navigate away from your page.</p></li><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy"><code><b>Permissions-Policy</b></code></a>: Browser features can be disabled to varying degrees with this header (recently renamed from <code>Feature-Policy</code>).</p></li><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy"><code><b>Content-Security-Policy</b></code></a>: And if you need fine-grained control over the content in your application, this header allows you to configure a number of security settings, including similar controls to the <code>X-Frame-Options</code> header.</p></li></ul><p>You can configure these headers to protect an <code>/app/*</code> path, with the following in your <code>_headers</code> file:</p>
            <pre><code>/app/*
  X-Frame-Options: DENY
  X-Content-Type-Options: nosniff
  Referrer-Policy: no-referrer
  Permissions-Policy: document-domain=()
  Content-Security-Policy: script-src 'self'; frame-ancestors 'none';</code></pre>
            
    <div>
      <h3>CORS</h3>
      <a href="#cors">
        
      </a>
    </div>
    <p>Modern browsers implement a security protection called <i>CORS</i> or Cross-Origin Resource Sharing. This prevents one domain from being able to force a user's action on another. Without CORS, a malicious site owner might be able to do things like make requests to unsuspecting visitors' banks and initiate a transfer on their behalf. However, with CORS, requests are prevented from one origin to another to stop the malicious activity.</p><p>There are, however, some cases where it is safe to allow these cross-origin requests. So-called, "<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests">simple requests</a>" (such as linking to an image hosted on a different domain) are permitted by the browser. Fetching these resources dynamically is often where the difficulty arises, and the browser is sometimes overzealous in its protection. Simple static assets on Pages are safe to serve to any domain, since the request takes no action and there is no visitor session. Because of this, a domain owner can attach CORS headers to specify exactly which requests can be allowed in the <code>_headers</code> file for fine-grained and explicit control.</p><p>For example, the use of the asterisk will enable any origin to request any asset from your Pages deployment:</p>
            <pre><code>/*
  Access-Control-Allow-Origin: *</code></pre>
            <p>To be more restrictive and limit requests to only be allowed from a 'staging' subdomain, we can do the following:</p>
            <pre><code>https://:project.pages.dev/*
  Access-Control-Allow-Origin: https://staging.:project.pages.dev</code></pre>
            
    <div>
      <h2>How we built support for custom headers</h2>
      <a href="#how-we-built-support-for-custom-headers">
        
      </a>
    </div>
    <p>To support all these use cases for custom headers, we had to build a new engine to determine which rules to apply for each incoming request. Backed, of course, by Workers, this engine supports splats and placeholders, and allows you to include those matched values in your headers.</p><p>Although we don't support all of its features, we've modeled this matching engine after the <a href="https://wicg.github.io/urlpattern/">URLPattern specification</a> which was recently shipped with Chrome 95. We plan to be able to fully implement this specification for custom headers once URLPattern lands in the Workers runtime, and there should hopefully be no breaking changes to migrate.</p>
    <div>
      <h2>Enhanced support for redirects</h2>
      <a href="#enhanced-support-for-redirects">
        
      </a>
    </div>
    <p>With this same engine, we’re bringing these features to your <code>_redirects</code> file as well. You can now configure your redirects with splats, placeholders and status codes as shown in the example below:</p>
            <pre><code>/blog/* https://blog.example.com/:splat 301
/products/:code/:name /products?name=:name&amp;code=:code
/submit-form https://static-form.example.com/submit 307</code></pre>
            
    <div>
      <h2>Get started</h2>
      <a href="#get-started">
        
      </a>
    </div>
    <p>Custom <a href="https://developers.cloudflare.com/pages/platform/headers">headers</a> and <a href="https://developers.cloudflare.com/pages/platform/redirects">redirects</a> for Cloudflare Pages can be configured today. Check out <a href="https://developers.cloudflare.com/pages/platform">our documentation</a> to get started, and let us know how you're using it in <a href="https://discord.gg/cloudflaredev">our Discord server</a>. We'd love to hear about what this unlocks for your projects!</p>
    <div>
      <h2>Coming up...</h2>
      <a href="#coming-up">
        
      </a>
    </div>
    <p>And finally, if a <code>_headers</code> file and enhanced support for <code>_redirects</code> just isn't enough for you, we also have something <i>big</i> coming very soon which will give you the power to build even more powerful projects. Stay tuned!</p> ]]></content:encoded>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[SEO]]></category>
            <guid isPermaLink="false">2Svf2ExXnAO2AwvgiHaSDg</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
        <item>
            <title><![CDATA[Optimizing images on the web]]></title>
            <link>https://blog.cloudflare.com/optimizing-images/</link>
            <pubDate>Wed, 15 Sep 2021 12:59:31 GMT</pubDate>
            <description><![CDATA[ A detailed breakdown of how best to optimize images for the web, a new tool to test a webpage's image performance, and explanation of how Cloudflare Images can help to improve your website's image experience. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4erH7OasTo8mE8mhF1oEu4/f83683295d2d6dede03fc6b38fb70faa/tXnAVVjW7s4o475UtWZNzRyZXKdKpRWniLRUziVX0ohuQehj0NDgNTW7FaMAE9ZUEdvpU04d4fR7_1XqVseW0mgA0fZT2E8KS_3c3GICC6HxpPWG5nMYmhm1b4zl.png" />
            
            </figure><p>Images are a massive part of the Internet. On the median web page, <a href="https://almanac.httparchive.org/en/2020/page-weight">images account for 51% of the bytes loaded</a>, so any improvement made to their speed or their size has a significant impact on performance.</p><p>Today, we are excited to announce Cloudflare’s Image Optimization Testing Tool <i>(as of JUL 2023, this tool is no longer available)</i>. Simply enter your website’s URL, and we’ll run a series of automated tests to determine if there are any possible improvements you could make in delivering optimal images to visitors.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2CZPi22VztOJrNnWuNCsmc/d115048e7177f11dc3b84b30c225147a/SCREENSHOT-2.png" />
            
            </figure>
    <div>
      <h2>How users experience speed</h2>
      <a href="#how-users-experience-speed">
        
      </a>
    </div>
    <p>Everyone who has ever browsed the web has experienced a website that was slow to load. Often, this is a result of poorly optimized images on that webpage that are either too large for purpose or that were embedded on the page with insufficient information.</p><p>Images on a page might take painfully long to load as pixels agonizingly fill in from top-to-bottom; or worse still, they might cause massive shifts of the page layout as the browser learns about their dimensions. These problems are a serious annoyance to users and as of August 2021, search engines punish pages accordingly.</p><p>Understandably, slow page loads have an adverse effect on a page's “bounce rate” which is the percentage of visitors which quickly move off of the page. On e-commerce sites in particular, the bounce rate typically has a direct monetary impact and pages are usually very image-heavy. It is critically important to optimize all the images on your webpages to reduce load on and egress from your origin, to improve your performance in search engine rankings and, ultimately, to provide a great experience for your users.</p>
    <div>
      <h2>Measuring speed</h2>
      <a href="#measuring-speed">
        
      </a>
    </div>
    <p>Since the end of August 2021, <a href="https://developers.google.com/search/blog/2020/11/timing-for-page-experience">Google has used the Core Web Vitals to quantify page performance when considering search results rankings</a>. These metrics are three numbers: <a href="https://web.dev/lcp/">Largest Contentful Paint (LCP)</a>, <a href="https://web.dev/fid/">First Input Delay (FID)</a>, and <a href="https://web.dev/cls/">Cumulative Layout Shift (CLS)</a>. They approximate the experience of loading, interactivity and visual stability respectively.</p><p>CLS and LCP are the two metrics we can improve by optimizing images. When CLS is high, this indicates that large amounts of the page layout is shifting as it loads. LCP measures the time it takes for the single largest image or text block in the viewport to render.</p><p>These can both be measured “in the field” with Real User Monitoring (RUM) analytics such as <a href="/start-measuring-web-vitals-with-browser-insights/">Cloudflare's Web Analytics</a>, or in a “lab environment” using <a href="https://images.cloudflare.com/">Cloudflare’s Image Optimization Testing Tool</a>.</p>
    <div>
      <h2>How to optimize for speed</h2>
      <a href="#how-to-optimize-for-speed">
        
      </a>
    </div>
    
    <div>
      <h3>Dimensions</h3>
      <a href="#dimensions">
        
      </a>
    </div>
    <p>One of the most impactful performance improvements a website author can make is ensuring they deliver images with appropriate dimensions. Images taken on a modern camera can be truly massive, and some recent flagship phones have gigantic sensors. The Samsung Galaxy S21 Ultra, for example, has a 108 MP sensor which captures a 12,000 by 9,000 pixel image. That same phone has a screen width of only 1440 pixels. It is physically impossible to show every pixel of the photo on that device: for a landscape photo, only 12% of pixel columns can be displayed.</p><p>Embedding this image on a webpage presents the same problem, but this time, that image and all of its unused pixels are sent over the Internet. Ultimately, this creates unnecessary load on the server, higher egress costs, and longer loading times for visitors.. This is exacerbated even further for visitors on mobile since they are often using a slower connection and have limits on their data usage. On a fast 3G connection, that 108 MP photo might consume 26 MB of both the visitor’s data plan and the website’s egress bandwidth, and take more than two minutes to load!</p><p>It might be tempting to always deliver images with the highest possible resolution to avoid “blocky” or pixelated images, but when resizing is done correctly, this is not a problem. “Blocky” artifacts typically occur when an image is processed multiple times (for example, an image is repeatedly uploaded and downloaded by users on a platform which compresses that image). Pixelated images occur when an image has been shrunk to a size smaller than the screen it is rendered on.</p><p>So, how can website authors avoid these pitfalls and ensure a correctly sized image is delivered to visitors’ devices? There are two main approaches:</p><ul><li><p><b>Media conditions with </b><code><b>srcset</b></code><b> and </b><code><b>sizes</b></code></p></li></ul><p>When embedding an image on a webpage, traditionally the author would simply pass a <code>src</code> attribute on an <code>img</code> tag:</p>
            <pre><code>&lt;img src="hello_world_12000.jpg" alt="Hello, world!" /&gt;</code></pre>
            <p><a href="https://caniuse.com/srcset">Since 2017, all modern browsers have supported the more dynamic <code>srcset</code> attribute</a>. This allows authors to set multiple image sources, depending on the matching media condition of the visitor’s browser:</p>
            <pre><code>&lt;img srcset="hello_world_1500.jpg 1500w,
             hello_world_2000.jpg 2000w,
             hello_world_12000.jpg 12000w"
     sizes="(max-width: 1500px) 1500px,
            (max-width: 2000px) 2000px,
            12000px"
     src="hello_world_12000.jpg"
     alt="Hello, world!" /&gt;</code></pre>
            <p>Here, with the <code>srcset</code> attribute, we're informing the browser that there are three variants of the image, each with a different intrinsic width: 1,500 pixels, 2,000 pixels and the original 12,000 pixels. The browser then evaluates the media conditions in the <code>sizes</code> attribute ( <code>(max-width: 1500px)</code> and <code>(max-width: 2000px)</code>) in order to select the appropriate image variant from the <code>srcset</code> attribute. If the browser's viewport width is less than 1500px, the <code>hello_world_1500.jpg</code> image variant will be loaded; if the browser's viewport width is between 1500px and 2000px, the <code>hello_world_2000.jpg</code> image variant will be loaded; and finally, if the browser's viewport width is larger than 2000px, the browser will fallback to loading the <code>hello_world_12000.jpg</code> image variant.</p><p>Similar behavior is also possible with a <code>picture</code> element, using the <code>source</code> child element which supports a variety of other selectors.</p><ul><li><p><b><b><b>Client Hints</b></b></b></p></li></ul><p>Client Hints are a standard that some browsers are choosing to implement, and some not. They are a set of HTTP request headers which tell the server about the client's device. For example, the browser can attach a <code>Viewport-Width</code> header when requesting an image which informs the server of the width of that particular browser's viewport (note this header is currently in the process of <a href="https://wicg.github.io/responsive-image-client-hints/#sec-ch-viewport-width">being renamed</a> to <code>Sec-CH-Viewport-Width</code>).</p><p>This simplifies the markup in the previous example greatly — in fact, no changes are required from the original simple HTML:</p>
            <pre><code>&lt;img src="hello_world_12000.jpg" alt="Hello, world!" /&gt;</code></pre>
            <p>If Client Hints are supported, when the browser makes a request for <code>hello_world_12000.jpg</code>, it might attach the following header:</p>
            <pre><code>Viewport-Width: 1440</code></pre>
            <p>The server could then automatically serve a smaller image variant (e.g. <code>hello_world_1500.jpg</code>), despite the request originally asking for <code>hello_world_12000.jpg</code> image.</p><p>By enabling browsers to request an image with appropriate dimensions, we save bandwidth and time for both your server and for your visitors.</p>
    <div>
      <h3>Format</h3>
      <a href="#format">
        
      </a>
    </div>
    <p>JPEG, PNG, GIF, WebP, and now, AVIF. AVIF is the latest image format with widespread industry support, and it often outperforms its preceding formats. AVIF supports transparency with an alpha channel, it supports animations, and it is typically 50% smaller than comparable JPEGs (vs. WebP's reduction of only 30%).</p><p><a href="/generate-avif-images-with-image-resizing/">We added the AVIF format to Cloudflare's Image Resizing product last year</a> as soon as Google Chrome added support. Firefox 93 (scheduled for release on October 5, 2021) will be Firefox's first stable release, and with both Microsoft and Apple as members of AVIF's <a href="https://aomedia.org/">Alliance for Open Media</a>, we hope to see support in Edge and Safari soon. Before these modern formats, we also saw innovative approaches to improving how an image loads on a webpage. <a href="https://blurha.sh/">BlurHash</a> is a technique of embedding a very small representation of the image inside the HTML markup which can be immediately rendered and acts as a placeholder until the final image loads. This small representation (hash) produced a blurry mix of colors similar to that of the final image and so eased the loading experience for users.</p><p><a href="/parallel-streaming-of-progressive-images/">Progressive JPEGs</a> are similar in effect, but are a built-in feature of the image format itself. Instead of encoding the image bytes from top-to-bottom, bytes are ordered in increasing levels of image detail. This again produces a more subtle loading experience, where the user first sees a low quality image which progressively “enhances” as more bytes are loaded.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/24SqYrCdUCp0ADM7W5sh11/ed8511ca138b4db9c92248b7db2cbbe1/Enhance.png" />
            
            </figure>
    <div>
      <h3>Quality</h3>
      <a href="#quality">
        
      </a>
    </div>
    <p>The newer image formats (WebP and AVIF) support lossless compression, unlike their predecessor, JPEG. For some uses, lossless compression might be appropriate, but for the majority of websites, speed is prioritized and this minor loss in quality is worth the time and bytes saved.</p><p>Optimizing where to set the quality is a balancing act: too aggressive and artifacts become visible on your image; too little and the image is unnecessarily large. <a href="https://opensource.google/projects/butteraugli">Butteraugli</a> and <a href="https://en.wikipedia.org/wiki/Structural_similarity">SSIM</a> are examples of algorithms which approximate our perception of image quality, but this is currently difficult to automate and is therefore best set manually. In general, however, we find that around 85% in most compression libraries is a sensible default.</p>
    <div>
      <h3>Markup</h3>
      <a href="#markup">
        
      </a>
    </div>
    <p>All of the previous techniques reduce the number of bytes an image uses. This is great for improving the loading speed of those images and the Largest Contentful Paint (LCP) metric. However, to improve the Cumulative Layout Shift (CLS) metric, we must minimize changes to the page layout. This can be done by informing the browser of the image size ahead of time.</p><p>On a poorly optimized webpage, images will be embedded without their dimensions in the markup. The browser fetches those images, and only once it has received the header bytes of the image can it know about the dimensions of that image. The effect is that the browser first renders the page where the image takes up zero pixels, and then suddenly redraws with the dimensions of that image before actually loading the image pixels themselves. This is jarring to users and has a serious impact on usability.</p><p>It is important to include dimensions of the image inside HTML markup to allow the browser to allocate space for that image before it even begins loading. This prevents unnecessary redraws and reduces layout shift. It is even possible to set dimensions when dynamically loading responsive images: by informing the browser of the height and width of the original image, assuming the aspect ratio is constant, it will automatically calculate the correct height, even when using a width selector.</p>
            <pre><code>&lt;img height="9000"
     width="12000"
     srcset="hello_world_1500.jpg 1500w,
             hello_world_2000.jpg 2000w,
             hello_world_12000.jpg 12000w"
     sizes="(max-width: 1500px) 1500px,
            (max-width: 2000px) 2000px,
            12000px"
     src="hello_world_12000.jpg"
     alt="Hello, world!" /&gt;</code></pre>
            <p>Finally, lazy-loading is a technique which reduces the work that the browser has to perform right at the onset of page loading. By deferring image loads to only just before they're needed, the browser can prioritize more critical assets such as fonts, styles and JavaScript. By setting the <code>loading</code> property on an image to <code>lazy</code>, you instruct the browser to only load the image as it enters the viewport. For example, on an e-commerce site which renders a grid of products, this would mean that the page loads faster for visitors, and seamlessly fetches images below the fold, as a user scrolls down. This is <a href="https://caniuse.com/loading-lazy-attr">supported by all major browsers except Safari</a> which currently has this feature hidden behind an experimental flag.</p>
            <pre><code>&lt;img loading="lazy" … /&gt;</code></pre>
            
    <div>
      <h3>Hosting</h3>
      <a href="#hosting">
        
      </a>
    </div>
    <p>Finally, you can improve image loading by hosting all of a page's images together on the same first-party domain. If each image was hosted on a different domain, the browser would have to perform a DNS lookup, create a TCP connection and perform the TLS handshake for every single image. When they are all co-located on a single domain (especially so if that is the same domain as the page itself), the browser can re-use the connection which improves the speed it can load those images.</p>
    <div>
      <h2>Test your website</h2>
      <a href="#test-your-website">
        
      </a>
    </div>
    <p>Today, we’re excited to announce the launch of <a href="https://images.cloudflare.com/">Cloudflare’s Image Optimization Testing Tool</a>. Simply enter your website URL, and we’ll run a series of automated tests to determine if there are any possible improvements you could make in delivering optimal images to visitors.</p><p>We use WebPageTest and Lighthouse to calculate the Core Web Vitals on two versions of your page: one as the original, and one with Cloudflare's best-effort automatic optimizations. These optimizations are performed using a Cloudflare Worker in combination with our Image Resizing product, and will transform an image's format, quality, and dimensions.</p><p>We report key summary metrics about your webpage's performance, including the aforementioned Cumulative Layout Shift (CLS) and Largest Contentful Page (LCP), as well as a detailed breakdown of each image on your page and the optimizations that can be made.</p>
    <div>
      <h2>Cloudflare Images</h2>
      <a href="#cloudflare-images">
        
      </a>
    </div>
    <p><a href="/announcing-cloudflare-images">Cloudflare Images</a> can help you to solve a number of the problems outlined in this post. By storing your images with Cloudflare and configuring a set of variants, we can deliver optimized images from our edge to your website or app. We automatically set the optimal image format and allow you to customize the dimensions and fit for your use-cases.</p><p>We're excited to see what you build with Cloudflare Images, and you can expect additional features and integrations in the near future. <a href="https://dash.cloudflare.com/sign-up/images">Get started with Images today from $6/month</a>.</p>
    <div>
      <h2>Watch on Cloudflare TV</h2>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Cloudflare Images]]></category>
            <guid isPermaLink="false">35szDDTJbHZORdWjXxUTzz</guid>
            <dc:creator>Greg Brimble</dc:creator>
        </item>
    </channel>
</rss>