<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Phil Hawksworth</title>
    <description>The latest articles on DEV Community by Phil Hawksworth (@philhawksworth).</description>
    <link>https://dev.to/philhawksworth</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F39876%2Fca69fd4b-e0f7-4c73-a724-476997ff6dde.jpg</url>
      <title>DEV Community: Phil Hawksworth</title>
      <link>https://dev.to/philhawksworth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/philhawksworth"/>
    <language>en</language>
    <item>
      <title>Avoiding lock-in for your image pipeline with Nuxt Image and Netlify Image CDN</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Fri, 19 Apr 2024 09:53:12 +0000</pubDate>
      <link>https://dev.to/netlify/avoiding-lock-in-for-your-image-pipeline-with-nuxt-image-and-netlify-image-cdn-3anc</link>
      <guid>https://dev.to/netlify/avoiding-lock-in-for-your-image-pipeline-with-nuxt-image-and-netlify-image-cdn-3anc</guid>
      <description>&lt;p&gt;Resizing and optimizing image assets in our web projects has become both an important part of the efforts to safeguard performance, and also a common developer experience or code efficiency wrinkle. Many frameworks seek to streamline this for users and developers alike, and often leverage image services such as Netlify Image CDN, Cloudinary, or Imgix. Nuxt Image does this in a way that does not lock you in to any one provider, and is incredibly simple to set up with Netlify.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Here, we'll look at the steps to adding Nuxt Image to a Nuxt project, and see how it is automatically powered by Netlify Image CDN when deployed to Netlify. We'll also see how this can be used and tested in a local development context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To code along as we go, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.netlify.com/cli/" rel="noopener noreferrer"&gt;Netlify CLI&lt;/a&gt; for local development with Netlify Image&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://app.netlify.com/singup" rel="noopener noreferrer"&gt;A Netlify account&lt;/a&gt; for deploying a version to test in production&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JFDI (just deploy it)
&lt;/h2&gt;

&lt;p&gt;If you'd prefer to just clone and deploy an example to explore, click the button below and you'll very quickly have an example Nuxt site using Netlify Image to power Nuxt Image deployed and ready to tinker with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/example-nuxt-image" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.netlify.com%2Fimg%2Fdeploy%2Fbutton.svg%3Fv%3D2" alt="Deploy to Netlify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Nuxt Image to a Nuxt project
&lt;/h2&gt;

&lt;p&gt;Nuxt Image is a module dedicated to providing image asset optimization, resizing, and associated markup generation for your Nuxt sites. If you have a project already, you can add it that, or if you'd prefer a totally clean start, use the &lt;a href="https://www.npmjs.com/package/nuxi" rel="noopener noreferrer"&gt;Nuxt CLI&lt;/a&gt; (nuxi) to quickly create a new starter Nuxt project to experiment with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nuxi@latest init my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add the Nuxt Image module as a dependency to your project
&lt;/h3&gt;

&lt;p&gt;The Nuxt CLI can help us with this too, which for convenience, we can use via &lt;code&gt;npx&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nuxi@latest module add image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tell your Nuxt project that you're using the module
&lt;/h3&gt;

&lt;p&gt;Adding the module to your Nuxt configuration file, &lt;code&gt;nuxt.config.js&lt;/code&gt;, will make &lt;code&gt;&amp;lt;NuxtImg&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;NuxtPicture&amp;gt;&lt;/code&gt; components available to use in your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nuxt/image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add an image to your application using &lt;code&gt;&amp;lt;NuxtImg&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Nuxt Image and Netlify Image CDN can serve images assets which are part of the site repo or sourced from an external resource. To start, let's add a local image and display it in a page template.&lt;/p&gt;

&lt;p&gt;Various &lt;a href="https://image.nuxt.com/providers/netlify#modifiers" rel="noopener noreferrer"&gt;attributes and modifiers&lt;/a&gt; can be set and passed along to the underlying image service provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;NuxtImg&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"owl.jpg"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; &lt;span class="na"&gt;fit=&lt;/span&gt;&lt;span class="s"&gt;"cover"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Nuxt Image in your local environment
&lt;/h2&gt;

&lt;p&gt;During development, you'll want to get a realistic picture (Yes, I saw this pun coming, and did nothing to avoid it. You're welcome) of how everything is working using the underlying image provider, in our case Netlify Image CDN. Luckily, we can gain access to this by simply running our local build with &lt;a href="https://docs.netlify.com/cli/local-development/#get-started-with-netlify-dev" rel="noopener noreferrer"&gt;Netlify Dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Netlify Dev is bundled into &lt;a href="https://dev.to/cli/"&gt;Netlify CLI&lt;/a&gt; and will &lt;a href="https://docs.netlify.com/cli/local-development/#project-detection" rel="noopener noreferrer"&gt;detect your local site&lt;/a&gt; characteristics and run your build for you when you run the command &lt;code&gt;netlify dev&lt;/code&gt; in your project directory (or &lt;code&gt;ntl dev&lt;/code&gt; if you want to &lt;a href="https://developers.netlify.com/guides/netlify-cli-alias-ntl" rel="noopener noreferrer"&gt;save a few keystrokes&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;By running your project with &lt;code&gt;netlify dev&lt;/code&gt; you'll gain local access to a number of the facilities of the Netlify platform such as redirects, serverless and edge functions, blob storage, and Image CDN (which is what we care about here)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;More specific local dev command control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If for some reason your project is not correctly detected and run by &lt;code&gt;netlify dev&lt;/code&gt;, or if you have some exotic local dev commands that you run, you can &lt;a href="https://docs.netlify.com/cli/local-development/#project-detection" rel="noopener noreferrer"&gt;configure this with a &lt;code&gt;netlify.toml&lt;/code&gt;file&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Explicitly specifying Netlify Image CDN as a provider
&lt;/h3&gt;

&lt;p&gt;Although Netlify will default to using Netlify CDN automatically, you can explicitly specify this by adding an &lt;code&gt;image&lt;/code&gt; object to your &lt;code&gt;nuxt.config.ts&lt;/code&gt; file and declaring your provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nuxt/image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;netlify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Allowing external image sources
&lt;/h4&gt;

&lt;p&gt;To use images from external sources in Nuxt Image, with the same optimizations, CDN caching, and manipulation as with your local images, you need to declare the allowed domains by adding a &lt;code&gt;domains&lt;/code&gt; array to your &lt;code&gt;nuxt.config.ts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nuxt/image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;netlify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;images.example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ummm... that's it
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;tl;dr&lt;/em&gt; could perhaps have been:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the dependency&lt;/li&gt;
&lt;li&gt;Add it to the config&lt;/li&gt;
&lt;li&gt;Use the component&lt;/li&gt;
&lt;li&gt;Ship it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to the thoughtful abstractions provided by Nuxt Image, this is all you need to do to use &lt;code&gt;&amp;lt;NuxtImg&amp;gt;&lt;/code&gt; with Netlify powering the image optimizations and manipulations. You might have noticed that we've not even added any mention of Netlify Image CDN to the codebase at this stage.&lt;/p&gt;

&lt;p&gt;Nuxt Image will automatically detect when it's being deployed to Netlify and use Netlify Image under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  The power of primitives
&lt;/h2&gt;

&lt;p&gt;One of the principles we value at Netlify is providing developers and framework authors access to powerful primitives to power their applications (or the frameworks that power the applications of others).&lt;/p&gt;

&lt;p&gt;Nuxt Image makes use of one such primitive perfectly here, offering convenience to Nuxt users without the need to learn about the underlying primitives (although &lt;a href="https://developers.netlify.com/guides/how-to-serve-optimized-images-using-netlify-image-cdn" rel="noopener noreferrer"&gt;you could use the Image CDN directly&lt;/a&gt; if you wished, or if your site didn't justify the use of a framework).&lt;/p&gt;

&lt;h2&gt;
  
  
  More information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nuxt.com/" rel="noopener noreferrer"&gt;Nuxt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://image.nuxt.com/" rel="noopener noreferrer"&gt;Nuxt Image module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://image.nuxt.com/providers/netlify" rel="noopener noreferrer"&gt;Netlify as a Nuxt Image provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/image-cdn/overview/#app" rel="noopener noreferrer"&gt;Netlify Image CDN docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/guides/how-to-serve-optimized-images-using-netlify-image-cdn"&gt;Using Netlify Image CDN directly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
      <category>nuxt</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Trigger a site update from anything that speaks HTTP with build hooks</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Tue, 02 Apr 2024 09:40:00 +0000</pubDate>
      <link>https://dev.to/netlify/trigger-a-site-update-from-anything-that-speaks-http-with-build-hooks-5h5n</link>
      <guid>https://dev.to/netlify/trigger-a-site-update-from-anything-that-speaks-http-with-build-hooks-5h5n</guid>
      <description>&lt;p&gt;Many might remember (or still be subjected to) long, drawn-out deployment processes. Complex, monolithic products often needed a time-consuming deployment process, taking many days and many people. CI/CD tooling transformed this aspect of web development and also unlocked the potential for highly performant and robust static assets to power sites that frequently update to stay fresh. Triggering a site build and deployment at the right moment is key to this, and build hooks give us that ability.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;We can manage and monitor the events that trigger updates to our sites with build hooks. In this guide, we'll see how simple it is to create build hooks from &lt;a href="https://app.netlify.com"&gt;the Netlify UI&lt;/a&gt; or using &lt;a href="https://developers.netlify.com/cli/"&gt;the CLI&lt;/a&gt;, and show how to conveniently test them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating build hooks in the Netlify UI
&lt;/h2&gt;

&lt;p&gt;By creating different build hooks, we can initiate new builds from all sorts of different events and see which event triggered our builds. To create a new build hook visit your &lt;strong&gt;Site configuration&lt;/strong&gt; in &lt;a href="https://app.netlify.com"&gt;the Netlify UI&lt;/a&gt; and go to &lt;strong&gt;Build &amp;amp; deploy&lt;/strong&gt; to find the &lt;strong&gt;Build hooks&lt;/strong&gt; panel.&lt;/p&gt;

&lt;p&gt;You can select the branch that you'd like to deploy and give your new build hook a meaningful name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h2Epr_vH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/full/blog-build-hook-settings.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h2Epr_vH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/full/blog-build-hook-settings.webp" alt="Build hook settings" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not possible to edit existing build hooks, but the list of your site's build hooks gives easy access to copy their URLs, and to copy a cURL command to test them out. You can also delete build hooks from here too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zli2dJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/full/blog-build-hook-list.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zli2dJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/full/blog-build-hook-list.webp" alt="A list of build hooks" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating build hooks with the Netlify CLI
&lt;/h2&gt;

&lt;p&gt;The Netlify CLI doesn't include commands to manage build hooks, but the Netlify API does. Since the CLI also gives access to any API command, you can use that facility to do this from your command line or programmatically should you wish.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Bonus Netlify CLI tip
&lt;/h3&gt;

&lt;p&gt;In addition to the built-in utilities in the Netlify CLI, you can also access API commands like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;netlify api {API—METHOD}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Try running &lt;code&gt;netlify api --list&lt;/code&gt; to show the available API methods and get quick access to their documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use the following command to list any build hooks on your site. (You'll need your Site ID, which you can get from the Netlify UI or from the CLI by running &lt;code&gt;netlify status&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netlify api listSiteBuildHooks &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"site_id": "YOUR—SITE—ID"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a new build hook using the CLI, use the &lt;code&gt;createSiteBuildHook&lt;/code&gt; API method, passing it the required data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netlify api createSiteBuildHook &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'
  {
    "site_id": "YOUR—SITE—ID",
    "body": {"title":"My build hook", "branch":"main"}
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will return information about your new build hook including its URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My build hook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"branch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.netlify.com/build_hooks/66058fe91febf5273753e516"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"draft"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-03-28T15:42:33.674Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"66058fe91febf5273753e516"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"site_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"41d9d252-cc2d-4600-bf60-XXXX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST https://api.netlify.com/build_hooks/66058fe91febf5273753e516 to trigger a build"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing a Build Hook
&lt;/h2&gt;

&lt;p&gt;Invoking a build hook is as simple as making an HTTP POST request to its URL. These URLs contain a unique, non-guessable path but no other form of authentication. It's recommended that you don't advertise your build hook URLs publicly, although it is trivial to delete a build hook and you can create as many as you need. (The ones in this post are all deleted, before you try to have some fun with me!)&lt;/p&gt;

&lt;p&gt;You can make an HTTP POST from your command line using cURL. There is no payload to pass, just an HTTP POST to the correct URL. Like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; https://api.netlify.com/build_hooks/&lt;span class="o"&gt;{&lt;/span&gt;YOUR-BUILD-HOOK-ID&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making the request, you'll see a new build identified with the label you gave to your build hook in your site's deploys in the &lt;a href="https://app.netlify.com"&gt;Netlify UI&lt;/a&gt;. Or you could look for the newly requested build by inspecting your deploys with the &lt;a href="https://developers.netlify.com/guides/streamline-your-workflow-with-the-official-netlify-raycast-extension/"&gt;Netlify Raycast extension&lt;/a&gt; if you prefer not to leave your desktop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safeguards against build thrashing
&lt;/h2&gt;

&lt;p&gt;Triggering builds programmatically from a variety of different sources and events has the potential to swamp Netlify with requests to build and deploy your site, so we have some safeguards against that, and some recommendations to further protect your build minutes.&lt;/p&gt;

&lt;p&gt;The Netlify Build Bots (as they are affectionately known internally at Netlify) have the intelligence to protect our systems and avoid wasting your build minutes. While a build is in progress, any additional build requests are queued behind it until the active build completes, at which time all subsequent build requests are skipped except for the most recent one. This avoids wasted builds that would have been quickly superseded and also gets the most recent request processed in a more timely way.&lt;/p&gt;

&lt;p&gt;You can also avoid making excessive build requests by being thoughtful about what events you choose to trigger a build.&lt;/p&gt;

&lt;p&gt;For instance, most headless content management systems (CMS) can post to a webhook for different types of events in their systems. Choose wisely here. For convenience, many save your content automatically as you type. This has saved my bacon (that is to say, my content) many times over the years, but also resulted in a lot of build requests to my sites as each keystroke created another request to build. Using the configuration of your chosen CMS to request a build based on &lt;em&gt;publishing&lt;/em&gt; events rather than &lt;em&gt;save&lt;/em&gt; events can be a good choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uses for build hooks
&lt;/h2&gt;

&lt;p&gt;Combining build hooks, with access to data and content from a variety of tools and services, and the ability to trigger calls to your build hooks from different events makes for a huge array of possibilities.&lt;/p&gt;

&lt;p&gt;By making APIs the interfaces between services, and by making the incredibly ubiquitous HTTP the means to communicate between services and trigger actions, we can compose many tools and services together with excellent hygiene and defined roles and responsibilities.&lt;/p&gt;

&lt;p&gt;Unifying content sources, digital asset management systems, version control systems, and so much more, all becomes viable and manageable.&lt;/p&gt;

&lt;p&gt;In addition to the more conventional uses we might imagine, I've seen many creative uses of build hooks too, with people calling on them to trigger site builds from Alexa, Apple Shortcuts on an iWatch, hardware buttons, and even motion sensors!&lt;/p&gt;

&lt;p&gt;Whether we're having fun or solving big, serious infrastructure and tooling challenges, the days of high friction and painful deployment processes are well and truly over.&lt;/p&gt;

&lt;h2&gt;
  
  
  More information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/configure-builds/build-hooks/#app"&gt;Full documentation on build hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.netlify.com/"&gt;Netlify CLI command reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://open-api.netlify.com/"&gt;Netlify API documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>tools</category>
      <category>automation</category>
    </item>
    <item>
      <title>Using custom error handling if a serverless function has crashed</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Mon, 25 Mar 2024 10:36:00 +0000</pubDate>
      <link>https://dev.to/netlify/using-custom-error-handling-if-a-serverless-function-has-crashed-1929</link>
      <guid>https://dev.to/netlify/using-custom-error-handling-if-a-serverless-function-has-crashed-1929</guid>
      <description>&lt;p&gt;When code is executed at request-time rather than at build time, and if it influences what visitors to your site see, then it is vitally important that you can control what happens should that code encounter an error. Displaying a message like "a serverless function has crashed" or a cryptic HTTP error code makes for a rough user experience. That's why Netlify edge functions give you some helpful options to gracefully handle errors, and fully control the experience passed on to the users.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;We'll look at how to configure the custom error handling available in Netlify edge functions, and try them out with some simplified examples which you can also clone and explore in your own local and deployed sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default error page
&lt;/h2&gt;

&lt;p&gt;If an error ever causes an edge function to crash, that error is written to the function logs and by default it will also be displayed as a response from the Edge Handler. This default function error page is helpful for the developer, but not so much for the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9afy8cvb2g3i8gwui54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9afy8cvb2g3i8gwui54.png" alt="The default edge function error page" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom error handling in edge functions
&lt;/h2&gt;

&lt;p&gt;You can configure this error handling behavior to customize the experience. You have three options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Show the default failure page&lt;/li&gt;
&lt;li&gt;Silently bypass the error&lt;/li&gt;
&lt;li&gt;Display your own custom error page&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Show the default failure page
&lt;/h3&gt;

&lt;p&gt;The custom error handling is configured directly in your edge function by adding an &lt;code&gt;onError&lt;/code&gt; property to the config. If you don't specify an &lt;code&gt;onError&lt;/code&gt; behavior, the default of &lt;code&gt;fail&lt;/code&gt; will be used, &lt;a href="https://example-edge-function-error-handling.netlify.app/unhandled-error"&gt;as you can see here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@netlify/edge-functions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Display the failure message&lt;/span&gt;
  &lt;span class="c1"&gt;// (This is the default behavior if not configured)&lt;/span&gt;
  &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Silently bypass the error
&lt;/h3&gt;

&lt;p&gt;By setting the &lt;code&gt;onError&lt;/code&gt; option to &lt;code&gt;bypass&lt;/code&gt;, an erroring edge function still throws an error which is entered into the error logs, but it does not halt the progress of the request chain. If an asset was to be returned from this request, that will still happen even though the function encountered an error.&lt;/p&gt;

&lt;p&gt;You can see that in this example, where an edge function is invoked on requests made to the &lt;a href="https://example-edge-function-error-handling.netlify.app/intended-page"&gt;intended page&lt;/a&gt;. Even though the function errors, you'll still reach the intended page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@netlify/edge-functions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Silently bypass the error&lt;/span&gt;
  &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bypass&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Display your own custom error page
&lt;/h3&gt;

&lt;p&gt;By setting the &lt;code&gt;onError&lt;/code&gt; option to hold any path on your site, starting with &lt;code&gt;/&lt;/code&gt;, the Edge function still throws an error which is entered into the error logs, but the user sees the result of am HTTP rewrite to the path of our choosing within the site. This allows us to let them down gently with whatever nicely designed experience we chose, while logging the error behind the scenes.&lt;/p&gt;

&lt;p&gt;You can see that in this example where an edge function is invoked on requests made to the &lt;a href="https://example-edge-function-error-handling.netlify.app/custom-error"&gt;this erroring route&lt;/a&gt; which results in you seeing the custom &lt;a href="https://github.com/philhawksworth/example-edge-function-error-handling/blob/main/www/error-page.html"&gt;error page&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@netlify/edge-functions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Redirect the user to any URL in your site&lt;/span&gt;
  &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/your-far-prettier-error-page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try for yourself
&lt;/h2&gt;

&lt;p&gt;Visiting these example links only showed you the view intended for the user. To see the error logging behind the scenes, and to experiment more, you can clone and deploy your own version of these simple examples by clicking the button below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/philhawksworth/example-edge-function-error-handling"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5a03ubW8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.netlify.com/img/deploy/button.svg%3Fv%3D2" alt="Deploy to Netlify" width="179" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;More examples of using and configuring edge functions in this &lt;a href="https://edge-functions-examples.netlify.app/"&gt;edge functions examples site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/edge-functions/optional-configuration/"&gt;Configuring edge functions documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/philhawksworth/example-edge-function-error-handling"&gt;Example repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>serverless</category>
      <category>webdev</category>
      <category>edge</category>
    </item>
    <item>
      <title>Build faster with the official Netlify Raycast extension</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Fri, 15 Mar 2024 10:25:00 +0000</pubDate>
      <link>https://dev.to/netlify/build-faster-with-the-official-netlify-raycast-extension-45e5</link>
      <guid>https://dev.to/netlify/build-faster-with-the-official-netlify-raycast-extension-45e5</guid>
      <description>&lt;p&gt;Raycast is an outstanding productivity tool for Mac OS offering all sorts of utilities, helpers, and deep integrations. It also has a thriving extension ecosystem. &lt;a href="https://www.raycast.com/netlify/netlify"&gt;Netlify's official Raycast extension&lt;/a&gt; utilizes Netlify's own APIs and offers a number of helpful tools and conveniences for developers building for the web with Netlify.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl457qu38ekgjz90bsy4l.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl457qu38ekgjz90bsy4l.jpeg" alt="Netlify Raycast commands" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;This post shows how to install the free Netlify Raycast extension, and explores some of the useful features it provides. Don't fancy reading? There is a quick video summary too.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install the free extension
&lt;/h1&gt;

&lt;p&gt;Existing Raycast users can just click the button below, or you can head over to the &lt;a href="https://www.raycast.com/netlify/netlify"&gt;Raycast site&lt;/a&gt; for more information and the latest release details for the Netlify extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.toraycast://extensions/netlify/netlify?source=netlify-developers-site"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wIx8cI6w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.raycast.com/netlify/netlify/install_button%402x.png%3Fv%3D1.1" alt="Install the Netlify Raycast extension" width="512" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/EVLUsV2XaQg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Direct docs access
&lt;/h1&gt;

&lt;p&gt;Quick access to the Netlify docs with less context switching is really nice. You can search the docs from within the Raycast UI and also add shortcuts to pages and locations &lt;a href="https://docs.netlify.com/"&gt;in the docs&lt;/a&gt; that you might visit regularly. Assign a hotkey or custom trigger for this and the friction reduces even further.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgoh1rwaf9c55m72ctfq9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgoh1rwaf9c55m72ctfq9.jpeg" alt="Netlify Raycast - search docs" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Explore sites and deploy resources
&lt;/h1&gt;

&lt;p&gt;Raycast lets you swiftly find and access management of your sites hosted on Netlify. It's a speedy way to browse, filter, and access your sites, so you can see what is happening in your Netlify projects without leaving your desktop, and then jump directly into the site, admin, or repo you're interested in. The convenience of accessing site details, scoping by team, and navigating to GitHub repositories is a real bonus. I use this a lot, especially as a stepping stone to exploring site deploys or site repos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhl9mq86b3w9dpqn1alk1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhl9mq86b3w9dpqn1alk1.jpeg" alt="Netlify Raycast - search sites" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also monitor your deploys this way. Access to the active and previous deploys is made more convenient thanks to the ability to filter by deploy context (such as branch, preview, or production), and by team. I love being able to see the status of a recent build quickly, and then quickly access the underlying pull request or code change that triggered the build. This is all available via the &lt;a href="https://app.netlify.com/"&gt;Netlify admin&lt;/a&gt;, but having it accessible quickly from the Raycast UI brings it closer to where I am working and speeds me up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ashk51kw4ihxtbdegaw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ashk51kw4ihxtbdegaw.jpeg" alt="Netlify Raycast - deploys" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Find local Netlify projects
&lt;/h1&gt;

&lt;p&gt;You can also use this to locate your Netlify projects on your local machine. Raycast makes them available for you to filter by name to quickly find projects and get into your code fast. After finding your local project, you can jump into it, open the underlying version control repo, open the Netlify admin for this project and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsvgwpaomshgu8y4qez6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsvgwpaomshgu8y4qez6.jpeg" alt="Netlify Raycast - local projects" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Review team actions
&lt;/h1&gt;

&lt;p&gt;Working in a team? There's extra help for you here too. The extension gives quick access to the &lt;a href="https://docs.netlify.com/accounts-and-billing/team-management/team-audit-log/#app"&gt;team audit log&lt;/a&gt;. This functionality can be really useful for teams collaborating on projects and accounts, allowing you to filter and review actions taken on the account by colleagues and collaborators. With the ability to filter by team and access the details of audit logs, team actions across projects become more transparent. Very handy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhrop4qrulv0v4ojpuye.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhrop4qrulv0v4ojpuye.jpeg" alt="Netlify Raycast - audit logs" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's more to explore in this extension, and you can also submit feature requests vis the Raycast code repo. Why not install it and give it a try?&lt;/p&gt;

&lt;h1&gt;
  
  
  Install the free extension
&lt;/h1&gt;

&lt;p&gt;You can visit &lt;a href="https://www.raycast.com/netlify/netlify"&gt;the Netlify Raycast extension page&lt;/a&gt; for more information about the extension and to install it from there, or if you're already a Raycast user, you can click the link below to install it directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.toraycast://extensions/netlify/netlify?source=netlify-developers-site"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wIx8cI6w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.raycast.com/netlify/netlify/install_button%402x.png%3Fv%3D1.1" alt="Install the Netlify Raycast extension" width="512" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tools</category>
      <category>raycast</category>
    </item>
    <item>
      <title>How to serve optimized images using Netlify's Image CDN</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Mon, 04 Mar 2024 13:11:00 +0000</pubDate>
      <link>https://dev.to/netlify/how-to-serve-optimized-images-using-52hj</link>
      <guid>https://dev.to/netlify/how-to-serve-optimized-images-using-52hj</guid>
      <description>&lt;p&gt;Not only can Netlify's Image CDN optimize image assets to improve site performance, but it can also handle common asset manipulation tasks on the fly. This cuts your site build times and powers valuable techniques such as responsive images and lazy loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use a URL like this to serve your image through Netlify's Image CDN:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/.netlify/images/?url=/images/your-image.jpeg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This post explains how you can quickly start using the Netlify Image CDN, and demonstrates some helpful techniques to make using this service fit conveniently into your development workflow. Learn how to use a single image to provide all of the required asset sizes for responsive images.&lt;/p&gt;

&lt;h2&gt;
  
  
  No setup required, just a URL
&lt;/h2&gt;

&lt;p&gt;To begin using Netlify's Image CDN, you don't need to install or enable anything in your Netlify Admin. You simply need to make requests for your assets via a special URL pattern that Netlify recognizes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# An image served from your site's files&lt;/span&gt;
/images/some-image.jpeg

&lt;span class="c"&gt;# The same image, but served from Netlify's optimized Image CDN&lt;/span&gt;
/.netlify/images/?url&lt;span class="o"&gt;=&lt;/span&gt;/images/some-image.jpeg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might recognize this special URL pattern from other tools you can use in your sites on Netlify, such as &lt;a href="https://www.netlify.com/platform/core/functions/"&gt;Netlify Functions&lt;/a&gt;. That &lt;code&gt;/.netlify/&lt;/code&gt; path is reserved on Netlify to access these sorts of helpers and utilities, so for those already using Netlify Functions this will already feel a little familiar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Convenience and future-proofing
&lt;/h2&gt;

&lt;p&gt;When using a service like this, I like to make it as unobtrusive in my code as possible. That way, should I ever wish to swap it out for an alternative, I can do so without a major refactor. Since the API is the URL, a small amount of abstraction using &lt;a href="https://docs.netlify.com/routing/redirects/"&gt;Netlify Redirects&lt;/a&gt; can help us achieve that.&lt;/p&gt;

&lt;p&gt;Let's create a convenient URL pattern we can use to serve the full-sized original image, but serve it from the Netlify Image CDN rather from our own site assets. A few lines in our &lt;code&gt;netlify.toml&lt;/code&gt; file will do that for us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[redirects]]&lt;/span&gt;
  &lt;span class="c"&gt;# Requests to URLs matching this pattern...&lt;/span&gt;
  &lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/images/full/:file"&lt;/span&gt;
  &lt;span class="c"&gt;# ...will resolve to this URL pattern&lt;/span&gt;
  &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"/.netlify/images/?url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;/images/:file&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="c"&gt;# ... and the status code of 200 will make this behave as a rewrite&lt;/span&gt;
  &lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other excellent Image CDN and optimization services out there like Cloudinary or Imgix also let you control their APIs through URLs. This means that should you need to upgrade to another service, perhaps to gain access to their more detailed asset manipulation features, you can do so by modifying the URL redirect rules here in your &lt;code&gt;netlify.toml&lt;/code&gt; (after creating accounts with them, for example), and leave all of the image URLs across your site untouched.&lt;/p&gt;

&lt;p&gt;With our redirect rule in place, a small change to the path used to source our images will let us choose to serve that image from the Image CDN.&lt;/p&gt;

&lt;p&gt;From this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- an image served from my assets folder --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/seedlings.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A photo of some green seedlings"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- an image served from my Netlify's Image CDN, originally sourced from my assets folder --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/full/seedlings.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A photo of some green seedlings"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tip: Assets can be on your sites or third party domains
&lt;/h3&gt;

&lt;p&gt;Netlify's Image CDN needs to source and ingest your image asset before it can optimize, cache, and serve it, which is done by specifying the URL where this can be found. This might be within your site or an external domain. For security reasons, requests for assets on external domains require a little config, which we'll get to later.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-demand image resizing and manipulation
&lt;/h2&gt;

&lt;p&gt;The Netlify Image CDN can also perform a number of image manipulation tasks for us. It's very common to need differently sized versions of images for optimal display, as seen in our responsive image example above. Doing this for every single image in your site as part of each build can be computationally expensive and make builds take a long time. Handing this off to Netlify to do on-demand the first time an asset is requested in a given size and then caching that result can simplify and speed up our build process.&lt;/p&gt;

&lt;p&gt;Including a &lt;code&gt;width&lt;/code&gt; or &lt;code&gt;height&lt;/code&gt; parameter in the URL will return a suitably resized image. Using just one or the other will retain the aspect ratio for us. Like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/.netlify/images/?url=/images/blue-flowers.jpg&amp;amp;width=100&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mml9xYuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/.netlify/images/%3Furl%3D/images/blue-flowers.jpg%26width%3D100" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mml9xYuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/.netlify/images/%3Furl%3D/images/blue-flowers.jpg%26width%3D100" alt="/.netlify/images/?url=/images/blue-flowers.jpg&amp;amp;width=100" width="100" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/.netlify/images/?url=/images/blue-flowers.jpg&amp;amp;width=200&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LFBds4I3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/.netlify/images/%3Furl%3D/images/blue-flowers.jpg%26width%3D200" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LFBds4I3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/.netlify/images/%3Furl%3D/images/blue-flowers.jpg%26width%3D200" alt="/.netlify/images/?url=/images/blue-flowers.jpg&amp;amp;width=200" width="200" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/.netlify/images/?url=/images/blue-flowers.jpg&amp;amp;width=400&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iiR-npyP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/.netlify/images/%3Furl%3D/images/blue-flowers.jpg%26width%3D400" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iiR-npyP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/.netlify/images/%3Furl%3D/images/blue-flowers.jpg%26width%3D400" alt="/.netlify/images/?url=/images/blue-flowers.jpg&amp;amp;width=400" width="400" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Image credit: &lt;a href="https://unsplash.com/photos/blue-flowers-plant-zt6970TlRyA?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;TOMOKO UJ, Unsplash&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip
&lt;/h3&gt;

&lt;p&gt;For information about all of the parameters we support for things like resizing, cropping, transforming image formats,&lt;br&gt;
  and more, take a look at the Transform Images section of &lt;a href="https://docs.netlify.com/image-cdn/overview/#transform-images"&gt;the Image CDN&lt;br&gt;
  documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Utility URLs for resizing
&lt;/h2&gt;

&lt;p&gt;Now let's make these URLs more convenient and better abstracted on our site. Similar to the redirect rule we created for our full-sized images (&lt;code&gt;/images/full/file-name.jpg&lt;/code&gt;), we could create some mappings for common sizes we might want so that the keywords &lt;code&gt;small&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, and &lt;code&gt;large&lt;/code&gt; each map to a URL with given width parameters. We could also make a rule which lets us pass a width parameter dynamically, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[redirects]]&lt;/span&gt;
  &lt;span class="c"&gt;# Get a width and file name value from the URL&lt;/span&gt;
  &lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/images/:width/:file"&lt;/span&gt;
  &lt;span class="c"&gt;# ...and pass them along as the correct request parameters&lt;/span&gt;
  &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"/.netlify/images/?url=/images/:file&amp;amp;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;:width&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Order matters
&lt;/h3&gt;

&lt;p&gt;Watch out for an easy mistake here. Netlify treats the order that rules appear in the &lt;code&gt;netlify.toml&lt;/code&gt; file as the order of priority, meaning that the first matching rule found is the one that will be applied. This is handy for creating logic in your rules.&lt;/p&gt;

&lt;p&gt;To make our example work as we would like, we need to add the rule that catches the variable input for width &lt;em&gt;after&lt;/em&gt; the rule that catches the word "full" in the same part of the URL as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;
&lt;span class="nn"&gt;[[redirects]]&lt;/span&gt;
  &lt;span class="c"&gt;# Serve a full size version&lt;/span&gt;
  &lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/images/full/:file"&lt;/span&gt;
  &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"/.netlify/images/?url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;/images/:file&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;

&lt;span class="nn"&gt;[[redirects]]&lt;/span&gt;
  &lt;span class="c"&gt;# ...or serve a resized version&lt;/span&gt;
  &lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/images/:width/:file"&lt;/span&gt;
  &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"/.netlify/images/?url=/images/:file&amp;amp;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;:width&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  &lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice. Now we have some intuitive URLs we can use to serve our images in any size.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/images/100/blue-flowers.jpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U1XZZac7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/100/blue-flowers.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U1XZZac7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/100/blue-flowers.jpg" alt="/images/100/blue-flowers.jpg" width="100" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/images/200/blue-flowers.jpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jW6SCpRG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/200/blue-flowers.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jW6SCpRG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/200/blue-flowers.jpg" alt="/images/200/blue-flowers.jpg" width="200" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/images/400/blue-flowers.jpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CMqIrKAn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/400/blue-flowers.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CMqIrKAn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developers.netlify.com/images/400/blue-flowers.jpg" alt="/images/400/blue-flowers.jpg" width="400" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(or &lt;a href="https://developers.netlify.com/images/full/blue-flowers.jpg"&gt;&lt;code&gt;/images/full/blue-flowers.jpg&lt;/code&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Different asset sizes for responsive images
&lt;/h2&gt;

&lt;p&gt;We've got everything we need to deliver the different asset sizes for use in our &lt;code&gt;srcset&lt;/code&gt; in responsive images. A full explanation of how the responsive images work is available at &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images"&gt;MDN&lt;/a&gt;, but here's a look the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/200/blue-flowers.jpg   200w,
    /images/400/blue-flowers.jpg   400w,
    /images/800/blue-flowers.jpg   800w,
    /images/1200/blue-flowers.jpg 1200w
  "&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 450px) 200px,
         (max-width: 850px) 400px,
         (max-width: 100px) 800px,
         1200px"&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/1200/blue-flowers.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Some blue flowers"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lovely! We're using readable, intuitive image URLs serving assets that are resized, optimized, and cached for us on demand. And should we decide to make changes to the size variant in our set of images we only need to edit a URL.&lt;/p&gt;

&lt;p&gt;Depending on what tools you are using to build your sites, this can also be a useful place for another bit of abstraction. A partial or a component that generates this markup for you when you pass it a &lt;em&gt;file name&lt;/em&gt; and an &lt;em&gt;alt&lt;/em&gt; tag (don't forget those &lt;code&gt;alt&lt;/code&gt; tags, friends!) can keep your code nice and clear, and formalize some common conventions across your sites for how you deliver responsive images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using images from remote domains
&lt;/h2&gt;

&lt;p&gt;The example here uses image assets which are part of the same site, so that relative paths are passed to Netlify's Image CDN.&lt;/p&gt;

&lt;p&gt;You can also feed the Image CDN assets from external domains. In order to prevent your site from becoming a gateway for anyone to perform unlimited image transformations on any assets, we give you control over which domains can be used. To do this, it's time to add another bit of config to your &lt;code&gt;netlify.toml&lt;/code&gt; file, where you can add an array of granted domains and use Reg Ex to describe detailed paths etc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[images]&lt;/span&gt;
  &lt;span class="py"&gt;remote_images&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"https://my-images.com/.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://animals.more-images.com/[bcr]at/.*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assets on relative paths, sourced from your site gain all the benefits of our atomic deploys and their default cache behaviors, so assets on the Image CDN don't become outdated as you deploy updates to your site. Assets on remote domains have different default cache characteristics. For information on how to control this, and other information about using remote domains with the Image CDN, take a look at &lt;a href="https://docs.netlify.com/image-cdn/overview/#remote-path"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus! Instant format optimization
&lt;/h3&gt;

&lt;p&gt;You can specify the format you'd like to use to deliver your assets by providing a format (&lt;a href="https://docs.netlify.com/image-cdn/overview/#format"&gt;&lt;code&gt;fm&lt;/code&gt;&lt;/a&gt;) parameter in the URL.&lt;/p&gt;

&lt;p&gt;However, if you &lt;em&gt;don't&lt;/em&gt; specify a format, the Netlify Image CDN will determine the most efficient format for the browser requesting the image, and automatically return that using the following logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use avif if accepted&lt;/li&gt;
&lt;li&gt;Otherwise, use webp if accepted&lt;/li&gt;
&lt;li&gt;If neither is accepted, use the original format&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Global infra in your local development
&lt;/h2&gt;

&lt;p&gt;To get access to these capabilities while running your code in a local development environment, run your build using &lt;code&gt;netlify dev&lt;/code&gt; which enables various Netlify Build and platform services locally, to smooth your development workflow.&lt;/p&gt;

&lt;p&gt;Running your local build this way will provide handlers to those special &lt;code&gt;/.netlify/&lt;/code&gt; URLs, including automatically replicating the image transformation behaviour so that you can review appropriately as you build.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;netlify dev&lt;/code&gt; command is made available by installing the &lt;a href="https://developers.netlify.com/cli/"&gt;Netlify CLI&lt;/a&gt; and will serve your sites locally in a way that provides access to Netlify Functions, Edge Functions, Redirects, Image CDN and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# Install Netlify CLI&lt;/span&gt;
npm i &lt;span class="nt"&gt;-g&lt;/span&gt; netlify-cli

&lt;span class="c"&gt;# Run your build with additional Netlify utilities&lt;/span&gt;
netlify dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it on one of your sites today!&lt;/p&gt;

&lt;h2&gt;
  
  
  More resources for handling images
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/image-cdn/overview/"&gt;Netlify Image CDN documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://image-cdn-playground.netlify.app/"&gt;Netlify Image CDN playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.netlify.com/integrations/cloudinary/"&gt;Cloudinary + Netlify integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://unpic.pics/"&gt;Unpic&lt;/a&gt; an open source library of helpers for images and image CDN abstraction&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hosting</category>
      <category>performance</category>
      <category>tricks</category>
    </item>
    <item>
      <title>Netlify trick: Adding pinned messages and thumbnails to projects</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Fri, 16 Feb 2024 15:02:00 +0000</pubDate>
      <link>https://dev.to/netlify/netlify-trick-adding-pinned-messages-and-thumbnails-to-projects-15bg</link>
      <guid>https://dev.to/netlify/netlify-trick-adding-pinned-messages-and-thumbnails-to-projects-15bg</guid>
      <description>&lt;p&gt;Anyone working with many projects over long periods of time in Netlify might be familiar with the task of seeking out a particular project in the Netlify admin. The sites page can get busy if you work on lots of projects, or if many people are collaborating and need to hop from project to project. Friction can kill your productivity momentum, so here are two little things that can make a big difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The Netlify admin supports custom thumbnail images and pinned messages on your site overviews. They are simple to use and this post will show you how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the best of site thumbnails
&lt;/h2&gt;

&lt;p&gt;When your site is deployed, Netlify will automatically generate a thumbnail image of the home page of your site which will be used to help you identify your sites in the site list page and in each sites overview page.&lt;/p&gt;

&lt;p&gt;You can toggle between letting Netlify generate the thumbnail or providing an image of your own. This can be particularly helpful if you have many sites which look similar from a distance, or if you have sites which don't have much meaningful UI because they focus on providing APIs or services for example.&lt;/p&gt;

&lt;p&gt;Specify a custom thumbnail image via the "Customize" button in your site's overview summary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrdgt4bolbgklek04cr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrdgt4bolbgklek04cr8.png" alt="Customize thumbnail UI" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Make team collaboration easier with pinned messages
&lt;/h2&gt;

&lt;p&gt;This much-requested feature makes it possible for you to locate valuable project information right in context and visible to collaborators (and let's be honest — future you) directly in the site overview page of your projects.&lt;/p&gt;

&lt;p&gt;While much documentation about a project might live in a readme file in its code repository, some information is not appropriate to place there, or might not be so discoverable to all those needing that information. Pinned messages support markdown and are perfect for communicating useful project information to your teammates, such as project purposes, project lifespans, links to issue trackers, and links to project communication channels.&lt;/p&gt;

&lt;p&gt;Or just emojis. You do you. 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu4uk10nhsvee4qaps3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu4uk10nhsvee4qaps3g.png" alt="Pinned message" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Just show me
&lt;/h2&gt;

&lt;p&gt;If you prefer to watch a quick video of this, here's how it looks.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/loxnyCz-ZGo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy a site to explore
&lt;/h2&gt;

&lt;p&gt;You don't have any sites deployed on Netlify already, but you really want to click around and play with this feature? No problem, a couple of clicks and we'll get you an example site. Click the button below to get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-feature-tour"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5a03ubW8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.netlify.com/img/deploy/button.svg%3Fv%3D2" alt="Deploy to Netlify" width="179" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tips</category>
      <category>tools</category>
    </item>
    <item>
      <title>Netlify tip: Explore and download assets generated by your builds</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Mon, 12 Feb 2024 12:32:00 +0000</pubDate>
      <link>https://dev.to/netlify/netlify-tip-explore-and-download-assets-generated-by-your-builds-5dp1</link>
      <guid>https://dev.to/netlify/netlify-tip-explore-and-download-assets-generated-by-your-builds-5dp1</guid>
      <description>&lt;p&gt;Understanding what assets your build generates is an important part of developing for the web. During local development that is usually easy to do, but what if you need compare the assets generated by a previous build? Or if you're looking for assurance that an asset is being faithfully generated by Netlify's build pipeline in the same way as it is locally? Netlify's &lt;em&gt;Deploy file explorer&lt;/em&gt; can help.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;You can download the output from any of your successful deploys in a single zip file, or by exploring the file structure generated by your builds. This post shows you where the &lt;a href="https://app.netlify.com"&gt;Netlify Admin UI&lt;/a&gt; you can do this, and gives you a simple one-click deploy to try this out for yourself if you've never deployed a site to Netlify before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://app.netlify.com/login"&gt;A Netlify account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A site successfully deployed to Netlify&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't have a site deployed to Netlify to experiment with yet, I've got you covered. Clicking the button below will create a new site for you from a simple template, set up the deployment pipeline, and perform your first deploy for your to explore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-feature-tour"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5a03ubW8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.netlify.com/img/deploy/button.svg%3Fv%3D2" alt="Deploy to Netlify" width="179" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Just show me
&lt;/h2&gt;

&lt;p&gt;If you prefer to watch a quick video of this, here's how it looks.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/r5L9yKMGroA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to find the Deploy file explorer
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;Deploy file explorer&lt;/em&gt; inspects the assets generated by completed build, so is available for each successful deploy regardless of if this is production, branch, or preview build.&lt;/p&gt;

&lt;p&gt;Navigate to the Deploys page of any of your sites in the &lt;a href="https://app.netlify.com"&gt;Netlify Admin&lt;/a&gt;, and then select any successful deploy.&lt;/p&gt;

&lt;p&gt;Below the &lt;em&gt;Deploy log&lt;/em&gt; panel, you'll find the &lt;em&gt;Deploy file explorer&lt;/em&gt; where you can navigate through the assets tree of your generated build, and search within it to find precisely what you are looking for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5a04lepnzqnlyjglbaq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5a04lepnzqnlyjglbaq2.png" alt="Explore the assets of any deploy" width="800" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Download the entire deploy
&lt;/h2&gt;

&lt;p&gt;You can also download any of your successful deploys in their entirety as a single zip file.&lt;/p&gt;

&lt;p&gt;The information panel above the &lt;em&gt;Deploy summary&lt;/em&gt; contains various pieces of information about your deploy. There you'll find a download link which will generate an archive for you to download as a single asset containing all of the files included in that deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ey7yxiiw6qm6wmiltl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ey7yxiiw6qm6wmiltl2.png" alt="Download your entire deploy" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's good practice not to commit build output to version control, so this feature is a useful way to quickly recover and explore historical archives of different versions of your sites.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>hosting</category>
      <category>tips</category>
    </item>
    <item>
      <title>Displaying your full-sized YouTube thumbnail or a custom OG image in a Twitter card</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Wed, 05 Jul 2023 15:19:00 +0000</pubDate>
      <link>https://dev.to/philhawksworth/displaying-your-full-sized-youtube-thumbnail-or-a-custom-og-image-in-a-twitter-card-g0h</link>
      <guid>https://dev.to/philhawksworth/displaying-your-full-sized-youtube-thumbnail-or-a-custom-og-image-in-a-twitter-card-g0h</guid>
      <description>&lt;p&gt;In days past, links to YouTube videos on Twitter used to show a nice full-sized thumbnail image. You could specify the poster image you wanted over in YouTube and it would appear along with an embedded video player. &lt;/p&gt;

&lt;p&gt;These days, links to YouTube videos have been downgraded to only show a small image card which is frustrating for anyone wanting to share their videos on Twitter with a visible and inviting call to action to watch them. In an effort to make their videos stand out and attract clicks again, some have taken to attaching a thumbnail images directly to their tweets which, while making them visually appealing, get in the way of click-throughs as people find themselves just seeing a larger version of the image rather than viewing the video.&lt;/p&gt;

&lt;p&gt;We can fix this with a crafty use of &lt;a href="https://www.netlify.com/products/?utm_source=hawksworx&amp;amp;utm_medium=findthatat-pnh&amp;amp;utm_campaign=devrel#netlify-edge-functions"&gt;Netlify's Edge Functions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I enriched my link shortener
&lt;/h2&gt;

&lt;p&gt;For some time, I've been using &lt;a href="https://docs.netlify.com/routing/overview/?utm_source=hawksworx&amp;amp;utm_medium=findthatat-pnh&amp;amp;utm_campaign=devrel"&gt;Netlify's redirects API&lt;/a&gt; to make &lt;a href="https://findthat.at"&gt;my own simple link shortener&lt;/a&gt;. It lets me create short URLs for sharing resources using a domain that I own and the knowledge that I don't need to depend on a third party link-sharing service.&lt;/p&gt;

&lt;p&gt;You can read about that in this blog post I wrote explaining it, including &lt;a href="https://github.com/kentcdodds/netlify-shortener"&gt;a handy little utility Kent C Dodds wrote&lt;/a&gt; to expand on this technique. (Also see &lt;a href="https://findthat.at/kcd-short"&gt;Kent's video explainer&lt;/a&gt; for even more background info)&lt;/p&gt;

&lt;p&gt;These days I use it in combination with &lt;a href="https://gist.github.com/philhawksworth/b77d876e865ac190a6bb849913d4a744"&gt;a little Raycast script&lt;/a&gt; to make creating new URLs a snap.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--swqMvjyt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9b30v1g863k5glfdd9mp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--swqMvjyt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9b30v1g863k5glfdd9mp.jpg" alt="Making a new short URL using Raycast" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having a link shortener like this provides a nice opportunity. It offers the chance to add some logic to customise what everyone (and everything) that follows those links will see.&lt;/p&gt;

&lt;p&gt;So, rather links to YouTube videos unfurling in Twitter like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FXR2ylty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ho1z5vqyrd33mcw8h6a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FXR2ylty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ho1z5vqyrd33mcw8h6a.jpg" alt="The small, default preview that Twitter shoes for links a YouTube video" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They can look &lt;a href="https://twitter.com/philhawksworth/status/1676503469350346753"&gt;like this&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GLMOIuQz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkqvg9xr91it1e7yeps0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GLMOIuQz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkqvg9xr91it1e7yeps0.jpg" alt="The larger preview that Twitter shows when we ask it nicely with a custom OG view" width="800" height="665"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to offer a different view to crawlers and unfurlers
&lt;/h2&gt;

&lt;p&gt;When you share a link on Twitter and on other tools and social networks, they visit the URL and "&lt;a href="https://indieweb.org/unfurl"&gt;unfurl&lt;/a&gt;" it in order to display a preview of what can be found there. We can give services like this hints about what we'd like them to show using metatags in the head of our HTML.&lt;/p&gt;

&lt;p&gt;Since Netlify introduced &lt;a href="https://www.netlify.com/blog/edge-functions-general-availability/?utm_source=hawksworx&amp;amp;utm_medium=findthatat-pnh&amp;amp;utm_campaign=devrel"&gt;Edge Functions&lt;/a&gt; we've had an ideal way to add a tiny bit of logic into our link shortener which will return a page template of our own to anything looking to unfurl the URL to display its &lt;a href="https://ogp.me/"&gt;opengraph&lt;/a&gt; image.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to detect if Twitter is visiting your URL
&lt;/h2&gt;

&lt;p&gt;While serving different experiences to visitors based on their brand of browser is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent"&gt;generally understood to be a bad idea&lt;/a&gt;, and we should instead use feature detection if we are trying to work around differences in browser support for features we need, here it is the ideal match for our needs. So we can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent"&gt;UserAgent sniffing&lt;/a&gt; to decide if we should just redirect the visitor to the page our short URL points at, or to show our own custom page instead.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/philhawksworth/shortener-with-custom-og/blob/a0218f52e89a2b70453e45a8ee593dfe2bd928e2/netlify/edge-functions/is-it-og.ts#L23-L38"&gt;code to do this in a netlify Edge Function&lt;/a&gt; is nice simple JavaScript (or TypeScript if you prefer)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Detecting if Twitter is the requesting user agent&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Twitter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Got something just for you, Twitter!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The URL we shared with Twitter is not a YouTube domain, it is on our custom domain, so Twitter won't automatically impose its own decisions about defaulting to a mini card. All we need to do is show it an HTML page with the appropriate opengraph data (which we can automatically get from the YouTube page that we're pointing at).&lt;/p&gt;

&lt;p&gt;To do this, our edge function fetches the open graph data from the destination URL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// fetching the open graph data from the destination page, &lt;/span&gt;
&lt;span class="c1"&gt;// and rendering it in a template&lt;/span&gt;

&lt;span class="c1"&gt;// Import Cheerio for easy DOM interrogation&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://esm.sh/cheerio@1.0.0-rc.12&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// get the og data from the final destination page via our redirect lookup&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://custom-short-link.netlify.app/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Grab some OG data from the site&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[property="og:title"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[property="og:description"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[property="og:site_name"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orginal_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[property="og:image"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the open graph data from the destination page, we can &lt;a href="https://github.com/philhawksworth/shortener-with-custom-og/blob/a0218f52e89a2b70453e45a8ee593dfe2bd928e2/netlify/edge-functions/is-it-og.ts#L40-L71"&gt;use it in our own page template&lt;/a&gt; to render our custom view when a request is made with Twitter's user agent string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Our page template. &lt;/span&gt;
&lt;span class="c1"&gt;// Just a string literal into which we can poke some variables&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../og-page.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Populate our OG page template&lt;/span&gt;
&lt;span class="c1"&gt;// and return it as HTML&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ogPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rootDomain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;orginal_image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YouTube&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;orginal_image&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ogPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;Now, just by making a convenient short link to any YouTube, when we share that link on Twitter it will display the large format image card within the tweet, but anyone clicking that preview card or following the link directly, will be taken to the video on YouTube. Nice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus. How to show custom OG images for third party URLs
&lt;/h2&gt;

&lt;p&gt;There's more! Now that we have this logic which displays a custom page view to Twitter, we can use it to show any OG image we like and not just relay the one specified at the destination URL.&lt;/p&gt;

&lt;p&gt;This lets us use &lt;em&gt;our own branding&lt;/em&gt; when we share a shortened link on Twitter. By expanding the list of user agent strings that we detect, we can add the same support for other places that unfurl URLs to show a preview image, like Slack, Mastodon, LinkedIn and others.&lt;/p&gt;

&lt;p&gt;A few more lines of logic in our function, and we can populate our custom template with our own OG image if we have one that matches the path in our short link. If not, not problem, just show the one intended by the owners of the destination page.&lt;/p&gt;

&lt;p&gt;I've used this to add my own OG image when the link I'm sharing doesn't have one of its own, or I've wanted to enhance it for my own purposes, like &lt;a href="https://twitter.com/philhawksworth/status/1671930204275589146"&gt;this one&lt;/a&gt; below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kGe7jxBX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3dxy5lzknk74g90523nq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kGe7jxBX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3dxy5lzknk74g90523nq.jpg" alt="How Twitter previews&amp;lt;/a&amp;gt; my &amp;lt;a href=&amp;quot;https://findthat.at/mfe&amp;quot;&amp;gt;custom link&amp;lt;/a&amp;gt; to a conference where I'll be speaking." width="800" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it for yourself
&lt;/h2&gt;

&lt;p&gt;You can experiment with this without needing to buy a domain or pay for anything. &lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/philhawksworth/shortener-with-custom-og&amp;amp;utm_source=hawksworx&amp;amp;utm_medium=findthatat-pnh&amp;amp;utm_campaign=devrel"&gt;Try deploying&lt;/a&gt; this &lt;a href="https://github.com/philhawksworth/shortener-with-custom-og"&gt;demo repo&lt;/a&gt; to Netlify to get a your own URL shortener including the edge function which detects unfurlers and renders its custom template. It also includes Kent's netlify-shortener utility script which has instructions on how to add a system wide command to quickly shorten links for you.&lt;/p&gt;

&lt;p&gt;The hardest part? Thinking of a good, short domain that you can register to use as your own short code domain. (You can register domains directly at Netlify too if you want to do the whole thing)&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Link shortener with custom OG image support &lt;a href="https://github.com/philhawksworth/shortener-with-custom-og"&gt;GitHub repo&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Automatically &lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/philhawksworth/shortener-with-custom-og&amp;amp;utm_source=hawksworx&amp;amp;utm_medium=findthatat-pnh&amp;amp;utm_campaign=devrel"&gt;clone the repo and deploy to Netlify&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kentcdodds/netlify-shortener"&gt;Kent C Dodd's Netlify-Shortener&lt;/a&gt; helper&lt;/li&gt;
&lt;li&gt;How to add &lt;a href="https://gist.github.com/philhawksworth/b77d876e865ac190a6bb849913d4a744"&gt;a Raycast script to make a new short link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/domains-https/netlify-dns/domain-registration/?&amp;amp;utm_source=hawksworx&amp;amp;utm_medium=findthatat-pnh&amp;amp;utm_campaign=devrel"&gt;Custom domains on Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How my &lt;a href="https://findtaht.at"&gt;findthat.at&lt;/a&gt; link shortener works&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>serverless</category>
    </item>
    <item>
      <title>What I learned from automating millions of web site deploys</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Mon, 26 Sep 2022 11:53:05 +0000</pubDate>
      <link>https://dev.to/philhawksworth/what-i-learned-from-automating-millions-of-web-site-deploys-3akg</link>
      <guid>https://dev.to/philhawksworth/what-i-learned-from-automating-millions-of-web-site-deploys-3akg</guid>
      <description>&lt;p&gt;Back in 2018 &lt;a href="https://twitter.com/philhawksworth/status/1020292946892152832" rel="noopener noreferrer"&gt;I decided to demonstrate&lt;/a&gt; how it had become feasible to automate the deployment of a web site thanks to modern web tooling and hosting services. I had been immersed in the world of enterprise web projects where deployments involved code and content freezes, a deployment team, holding your breath, and hoping for the best. the idea was triggered by this throw-away tweet from &lt;a href="https://twitter.com/zachleat/" rel="noopener noreferrer"&gt;Zach Leatherman&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Free side project idea: HTML-only static site generated clock that deploys a new version to &lt;a href="https://twitter.com/netlify" rel="noopener noreferrer"&gt;@netlify&lt;/a&gt; every minute&lt;br&gt;
— &lt;a href="https://twitter.com/zachleat/status/1020034115817680896" rel="noopener noreferrer"&gt;Zach Leatherman&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I made &lt;a href="https://setyourwatchby.netlify.app" rel="noopener noreferrer"&gt;setyourwatchby.netlify.app&lt;/a&gt;, a site which displayed the time. No client-side JavaScript to get the correct time for each visitor, just HTML containing the time that the site was generated as part of an automated build and deployment (and localised pages served up thanks to some &lt;a href="https://docs.netlify.com/routing/redirects/?utm_campaign=devex_pnh&amp;amp;utm_source=devto&amp;amp;utm_medium=web&amp;amp;utm_content=night-night-setyourwatch" rel="noopener noreferrer"&gt;CDN routing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I've &lt;a href="https://www.netlify.com/blog/2018/08/02/exploring-the-potential-of-friction-free-deployments/?utm_campaign=devex_pnh&amp;amp;utm_source=devto&amp;amp;utm_medium=web&amp;amp;utm_content=night-night-setyourwatch" rel="noopener noreferrer"&gt;described this in some detail in the past&lt;/a&gt;, but let's move along.&lt;/p&gt;

&lt;p&gt;The point I was making was that the friction and risk in deploying updates to a site had been so dramatically reduced, that it was now safe to perform unattended deployments automatically every single minute of the day.&lt;/p&gt;

&lt;p&gt;From 2018 to 2022 the site has been automatically rebuilt and redeployed millions of times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time and technology moves on
&lt;/h2&gt;

&lt;p&gt;As my &lt;em&gt;millions&lt;/em&gt; of site deploy logs on Netlify will illustrate, time moves on. Reliable build automation has become readily available for developers, even in the enterprise space. But deploying every minute is silly, really. It's fine for making a point as part of a demo, but we can be far more efficient and responsible than that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawr5xxuooxul6p1wfkps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawr5xxuooxul6p1wfkps.png" alt="The Netlify deploy screen showing a list of many deployments "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I needed to retire the demo site, but also wanted to make sure that you, dear reader, still had a way to tell the time! &lt;a href="https://setyourwatchby.netlify.app" rel="noopener noreferrer"&gt;setyourwatchby.netlify.app&lt;/a&gt; still had to function even after I turned off the scheduled builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge Functions to the rescue
&lt;/h2&gt;

&lt;p&gt;The arrival of Edge Functions saved the day. &lt;a href="https://www.netlify.com/products/#netlify-edge-functions" rel="noopener noreferrer"&gt;Netlify's Edge Functions&lt;/a&gt; are a low latency serverless runtime which can handle HTTP requests at locations close to the user and modify the HTTP response being returned. They provide a way to dynamically service every HTTP request without the need to manage and maintain a server. They're JavaScript, so I could just write &lt;a href="https://github.com/philhawksworth/html-time/blob/b9722a2e532e07ada5c9e2472f38e518e2385371/netlify/edge-functions/time.ts" rel="noopener noreferrer"&gt;a single function&lt;/a&gt; and be done.&lt;/p&gt;

&lt;p&gt;That's what you'll find if you visit &lt;a href="https://setyourwatchby.netlify.app" rel="noopener noreferrer"&gt;setyourwatchby.netlify.app&lt;/a&gt; now. Your request will be intercepted by an Edge Function running on Netlify's CDN which will determine your locale based on your IP address, and insert your current time into the HTML that it is sending to you.&lt;/p&gt;

&lt;p&gt;No more regular redeployments for this little demo site.&lt;/p&gt;

&lt;h2&gt;
  
  
  But what did I learn?
&lt;/h2&gt;

&lt;p&gt;Over the course of millions of unattended deployments, I did learn a few things.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Don't let your mistakes "leave the kitchen"
&lt;/h3&gt;

&lt;p&gt;Borrowing this notion from the catering trade, it's fine for mistakes to happen in the kitchen, but they must never reach the diner. Automating deployment on this (or any) scale is possible thanks to the model where builds which fail do not result in a deployment being published. &lt;/p&gt;

&lt;p&gt;My logs show that I had a few handfuls of builds which failed over the course of the millions of deployments since 2018, but they never worried me. The previous good deploy would always be visible until replaced by a new one, so at worst the time would be a wrong for one minute if a build broke or was skipped.&lt;/p&gt;

&lt;p&gt;This level of confidence in automation is key to its success. And these days we include all sorts of tests to our automated builds to check for accessibility, performance, and other integrity before they can "leave the kitchen" and take their final journey out to the hosting infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Knowledge is power
&lt;/h3&gt;

&lt;p&gt;A model of &lt;a href="https://jamstack.org/glossary/immutable/" rel="noopener noreferrer"&gt;immutable deployments&lt;/a&gt;, where each new build becomes an instance of the site which can live on in perpetuity, is incredibly powerful and liberating. By retaining every "known state" of a site over the course of its life, you gain the ability to redeploy any previous version of the site in milliseconds. Or to address any version of the site via a unique URL. Risk plummets when you know that you're not disrupting the integrity of your site, and can always revert.&lt;/p&gt;

&lt;p&gt;For posterity, &lt;a href="https://6177423cb626b90007b2a5d1--setyourwatchby.netlify.app/" rel="noopener noreferrer"&gt;here is what the site looked like&lt;/a&gt; the very last time it was automatically redeployed.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Automating got easier
&lt;/h3&gt;

&lt;p&gt;In 2018, I used a third party service to trigger a build of the site every minute. You can create webhooks on Netlify which trigger a build when called so this worked nicely.&lt;/p&gt;

&lt;p&gt;Since then, Netlify released &lt;a href="https://www.netlify.com/products/?utm_campaign=devex_pnh&amp;amp;utm_source=devto&amp;amp;utm_medium=web&amp;amp;utm_content=night-night-setyourwatch/#scheduled-functions" rel="noopener noreferrer"&gt;Scheduled Functions&lt;/a&gt; which give a cron-like interface for executing a serverless function. If I were to need to redeploy a site regularly these days, I'd use these to reduce the number of external services in play and make my life a little simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try Edge Functions yourself
&lt;/h2&gt;

&lt;p&gt;If you want to learn more about Netlify Edge Functions you can &lt;a href="https://edge-functions-examples.netlify.app/?utm_campaign=devex_pnh&amp;amp;utm_source=devto&amp;amp;utm_medium=web&amp;amp;utm_content=night-night-setyourwatch" rel="noopener noreferrer"&gt;explore some examples here&lt;/a&gt;, or &lt;a href="https://docs.netlify.com/edge-functions/overview/?utm_campaign=devex_pnh&amp;amp;utm_source=devto&amp;amp;utm_medium=web&amp;amp;utm_content=night-night-setyourwatch" rel="noopener noreferrer"&gt;visit the docs&lt;/a&gt;. Scheduled Functions are also very handy and simple to use, and you can find &lt;a href="https://docs.netlify.com/netlify-labs/experimental-features/scheduled-functions/?utm_campaign=devex_pnh&amp;amp;utm_source=devto&amp;amp;utm_medium=web&amp;amp;utm_content=night-night-setyourwatch" rel="noopener noreferrer"&gt;their docs here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, if you want to know the time, you can still visit &lt;a href="https://setyourwatchby.netlify.app" rel="noopener noreferrer"&gt;setyourwatchby.netlify.app&lt;/a&gt;, but I suspect you might have some other resources to help you with that :)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>serverless</category>
      <category>edge</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>Seeing what triggered a build for confidence in each commit</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Sat, 25 Dec 2021 23:27:04 +0000</pubDate>
      <link>https://dev.to/netlify/seeing-what-triggered-a-build-for-confidence-in-each-commit-1j2b</link>
      <guid>https://dev.to/netlify/seeing-what-triggered-a-build-for-confidence-in-each-commit-1j2b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Throughout December we'll be &lt;a href="https://dev.to/blog/2021/12/01/highlighting-a-different-netlify-feature-each-day-in-december/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;highlighting a different Netlify feature each day&lt;/a&gt;. It might just be the thing you need to unlock those creative juices, and &lt;a href="https://www.netlify.com/blog/2021/12/01/dusty-domains-your-forgotten-domains-raise-money-for-charity/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;dust off that domain&lt;/a&gt; you registered but never deployed! Keep an eye &lt;a href="https://www.netlify.com/blog/2021/12/01/highlighting-a-different-netlify-feature-each-day-in-december/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;on the blog&lt;/a&gt; and on &lt;a href="https://twitter.com/netlify"&gt;Twitter&lt;/a&gt; for each feature!&lt;br&gt;
There are a number of ways to deploy a site to Netlify, or to trigger a build. So it can be helpful to see what code or content changes brought about an update to your site.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perhaps a build was initiated by a &lt;a href="https://www.netlify.com/blog/2021/12/22/power-your-site-with-apis-and-build-hooks/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;build hook&lt;/a&gt;, in which case you’ll see that indicated in your Deploys page. But what if you are using &lt;a href="https://netlify.com/products/build/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;Netlify Build&lt;/a&gt; to build your site whenever you push code changes to you repo?&lt;/p&gt;

&lt;p&gt;Once again, the Deploys page in your project’s &lt;a href="https://app.netlify.com/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;Netlify admin&lt;/a&gt; holds the answer.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mlvLwiDZR_E"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Every deploy which was triggered by a code change includes a link to the commit. It gives you complete insight into what changes were responsible for the latest updates on your site. And into what to expect in the build.&lt;/p&gt;

&lt;p&gt;Click on the git hash visible in each deploy summary to take you directly to that commit in your GitHub, GitLab, or Bitbucket repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  More information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/configure-builds/get-started/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;Docs: Configure continuous deployments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/site-deploys/create-deploys/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=link-to-commit"&gt;Docs: Creating deploys&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>netlify</category>
      <category>development</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Monitor all of your team's projects with team audit logs</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Fri, 24 Dec 2021 21:44:28 +0000</pubDate>
      <link>https://dev.to/netlify/monitor-all-of-your-teams-projects-with-team-audit-logs-905</link>
      <guid>https://dev.to/netlify/monitor-all-of-your-teams-projects-with-team-audit-logs-905</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Throughout December we'll be &lt;a href="https://dev.to/blog/2021/12/01/highlighting-a-different-netlify-feature-each-day-in-december/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=team-logs"&gt;highlighting a different Netlify feature each day&lt;/a&gt;. It might just be the thing you need to unlock those creative juices, and &lt;a href="https://www.netlify.com/blog/2021/12/01/dusty-domains-your-forgotten-domains-raise-money-for-charity/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=team-logs"&gt;dust off that domain&lt;/a&gt; you registered but never deployed! Keep an eye &lt;a href="https://www.netlify.com/blog/2021/12/01/highlighting-a-different-netlify-feature-each-day-in-december/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=team-logs"&gt;on the blog&lt;/a&gt; and on &lt;a href="https://twitter.com/netlify"&gt;Twitter&lt;/a&gt; for each feature!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When many people come together to collaborate on a project or on many projects, it can be difficult to keep track of what is happening. That’s why we created &lt;a href="https://docs.netlify.com/accounts-and-billing/team-management/team-audit-log/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=team-logs"&gt;Team Audit logs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Team audit logs give any team administrator a heartbeat view of all of the actions taken by  members of a Netlify team.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/kbLQHvEiCHo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now, you have on place to check to see which of your projects have been deployed or updated and when, which projects have been rolled back and by whom, and many other activities which might be useful to know about.&lt;/p&gt;

&lt;p&gt;Teams bring all sorts of useful ways to collaborate on all of your web projects in Netlify. And access to this summary of actions is a great part of monitoring the health and productivity of your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  More information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.netlify.com/pricing/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=team-logs"&gt;Team pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/accounts-and-billing/team-management/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=team-logs"&gt;Docs: Team overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>netlify</category>
      <category>collaboration</category>
      <category>logging</category>
    </item>
    <item>
      <title>Event notifications provide information and integrations</title>
      <dc:creator>Phil Hawksworth</dc:creator>
      <pubDate>Thu, 23 Dec 2021 20:01:22 +0000</pubDate>
      <link>https://dev.to/netlify/event-notifications-provide-information-and-integrations-341n</link>
      <guid>https://dev.to/netlify/event-notifications-provide-information-and-integrations-341n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Throughout December we'll be &lt;a href="https://dev.to/blog/2021/12/01/highlighting-a-different-netlify-feature-each-day-in-december/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;highlighting a different Netlify feature each day&lt;/a&gt;. It might just be the thing you need to unlock those creative juices, and &lt;a href="https://www.netlify.com/blog/2021/12/01/dusty-domains-your-forgotten-domains-raise-money-for-charity/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;dust off that domain&lt;/a&gt; you registered but never deployed! Keep an eye &lt;a href="https://www.netlify.com/blog/2021/12/01/highlighting-a-different-netlify-feature-each-day-in-december/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;on the blog&lt;/a&gt; and on &lt;a href="https://twitter.com/netlify"&gt;Twitter&lt;/a&gt; for each feature!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Knowledge is power! &lt;/p&gt;

&lt;p&gt;Knowing what events have taken place in your Netlify project, and being able to trigger actions based on those events, is pretty bloomin’ powerful too!&lt;/p&gt;

&lt;p&gt;Netlify creates a variety of events throughout the lifecycle of your site deployments and for other services we provide for your sites, such as form submissions. Each of these events can create notifications and trigger actions elsewhere.&lt;/p&gt;

&lt;p&gt;Combining tools and services using events and triggers opens up all kinds of fun possibilities for your projects!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4a1mYp1b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://docs.netlify.com/images/site-deploys-outgoing-notifications.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4a1mYp1b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://docs.netlify.com/images/site-deploys-outgoing-notifications.png" alt="Notification options" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's happening?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.netlify.com/blog/2021/12/16/accepting-form-submissions-without-a-server/"&gt;Somebody submitted data&lt;/a&gt; to one of your forms? &lt;a href="https://docs.netlify.com/forms/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;We’ll let you know.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to be notified if your site has been deployed, or if a deployment has failed? &lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;We have notifications for that.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to know if a pull request has triggered a build? &lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;Yep, we can let you know that too&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a list of events related to builds and deploys that we can inform you about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deploy started&lt;/strong&gt;: Emitted when Netlify starts building your site for a new deploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy succeeded&lt;/strong&gt;: Emitted when Netlify finishes uploading a new deploy to our CDN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy failed&lt;/strong&gt;: Emitted when a deploy does not complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy locked&lt;/strong&gt;: Emitted when the site is &lt;a href="https://docs.netlify.com/site-deploys/manage-deploys/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#locked-deploys"&gt;locked to a published deploy&lt;/a&gt;, stopping auto publishing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy unlocked&lt;/strong&gt;: Emitted when deploys are unlocked, resuming auto publishing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy request pending&lt;/strong&gt;: Emitted when an untrusted deploy requires approval to begin building, as specified by the site’s &lt;a href="https://docs.netlify.com/configure-builds/environment-variables/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#sensitive-variable-policy"&gt;sensitive variable policy&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy request accepted&lt;/strong&gt;: Emitted when an untrusted deploy request is accepted and can begin building.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy request rejected&lt;/strong&gt;: Emitted when an untrusted deploy request is rejected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More event notification details can be found &lt;a href="https://docs.netlify.com/monitor-sites/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;in the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of notifications
&lt;/h2&gt;

&lt;p&gt;All of these events can trigger notifications. And you can configure what type of notification you receive for each event. Notification types include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#outgoing-webhooks"&gt;Outgoing webhooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#github-commit-checks"&gt;GitHub commit checks&lt;/a&gt; and &lt;a href="https://docs.netlify.com/site-deploys/notifications/#github-pull-request-comments"&gt;GitHub pull request comments&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#gitlab-commit-statuses"&gt;GitLab commit statuses&lt;/a&gt; and &lt;a href="https://docs.netlify.com/site-deploys/notifications/#gitlab-merge-request-comments"&gt;GitLab merge request comments&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#slack-notifications"&gt;Slack notifications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications#email-notifications"&gt;Email notifications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/monitor-sites/notifications/"&gt;and more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/site-deploys/notifications/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;Docs: Deploy notifications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.netlify.com/blog/2016/07/18/shiny-slack-notifications-from-netlify/?utm_campaign=featdaily21&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_content=notifications"&gt;Shiny Slack Notifications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>netlify</category>
      <category>notifications</category>
      <category>events</category>
    </item>
  </channel>
</rss>
