<?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: felipecarrillo100</title>
    <description>The latest articles on DEV Community by felipecarrillo100 (@felipecarrillo100).</description>
    <link>https://dev.to/felipecarrillo100</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%2F103527%2F46a7a41e-48fc-4e99-8ab8-549bf3549ec6.png</url>
      <title>DEV Community: felipecarrillo100</title>
      <link>https://dev.to/felipecarrillo100</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/felipecarrillo100"/>
    <language>en</language>
    <item>
      <title>CloudFront A/B Testing Without Cache Fragmentation: The Shadow Origin Pattern</title>
      <dc:creator>felipecarrillo100</dc:creator>
      <pubDate>Tue, 17 Mar 2026 04:11:09 +0000</pubDate>
      <link>https://dev.to/felipecarrillo100/cloudfront-ab-testing-without-cache-fragmentation-the-shadow-origin-pattern-192c</link>
      <guid>https://dev.to/felipecarrillo100/cloudfront-ab-testing-without-cache-fragmentation-the-shadow-origin-pattern-192c</guid>
      <description>&lt;p&gt;In AWS architectures, there is a silent trade-off that often goes unnoticed—until your AWS bill spikes or your latency graphs degrade:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Personalization vs. Cache Efficiency&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The common approach to A/B testing—executing logic in a &lt;strong&gt;viewer-request&lt;/strong&gt; hook and varying the &lt;strong&gt;cache key&lt;/strong&gt; using cookies—seems convenient, but it is an architectural trap.&lt;/p&gt;

&lt;p&gt;By introducing variants into the cache key, you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fragment your global edge cache&lt;/li&gt;
&lt;li&gt;Destroy your &lt;strong&gt;Cache Hit Ratio (CHR)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Increase S3 origin load and egress costs&lt;/li&gt;
&lt;li&gt;Reintroduce cold-start latency for users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a better way.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 The Solution: The Shadow Origin Pattern
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Shadow Origin Pattern&lt;/strong&gt; is a technique where the public request URI remains unchanged, while the origin fetch path is internally rewritten &lt;em&gt;after a cache miss&lt;/em&gt;. Instead of exposing variants to the CDN cache key, we move the decision &lt;strong&gt;behind the cache layer&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Architecture: Performance-First Routing
&lt;/h2&gt;

&lt;p&gt;The goal is simple: &lt;strong&gt;Do not fragment the cache key at the edge.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Request (Cache Key):&lt;/strong&gt; &lt;code&gt;/shop&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal Origin Fetch (after cache miss):&lt;/strong&gt; &lt;code&gt;/variants/B/shop&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is achieved using a &lt;strong&gt;Lambda@Edge &lt;code&gt;origin-request&lt;/code&gt; hook&lt;/strong&gt;, which runs &lt;em&gt;only after CloudFront determines the object is not in cache&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why this is powerful
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The cache key remains &lt;strong&gt;clean and stable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Variants are resolved &lt;strong&gt;internally&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Each variant is cached efficiently once fetched.&lt;/li&gt;
&lt;li&gt;No unnecessary duplication of edge cache entries.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. The Implementation: The “Shadow” Hook
&lt;/h2&gt;

&lt;p&gt;This Lambda@Edge function acts as a precise traffic controller.&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="cm"&gt;/**
 * Lambda@Edge: Origin Request Trigger
 * Goal: Internal URI mutation for high-CHR A/B Testing
 */&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Remove this line in AWS production&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hookType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;origin-request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;cf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&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="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="c1"&gt;// 1. Determine User Segment&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;control&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;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;if &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="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Variant=B&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="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&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;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Internal Path Mutation&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;variant&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/variants/B&lt;/span&gt;&lt;span class="p"&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;uri&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="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. S3 OAC Normalization&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&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;blockquote&gt;
&lt;p&gt;💡 &lt;em&gt;Save this file as `ab-testing.js&lt;/em&gt;`&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  ⚠️ Critical AWS Configuration (Do Not Skip)
&lt;/h3&gt;

&lt;p&gt;This function runs at the &lt;strong&gt;origin-request&lt;/strong&gt; stage. Unlike &lt;code&gt;viewer-request&lt;/code&gt;, cookies are &lt;strong&gt;not automatically available&lt;/strong&gt;. You &lt;strong&gt;must&lt;/strong&gt; configure CloudFront to forward them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cache Policy:&lt;/strong&gt; Cookies -&amp;gt; Include (or whitelist &lt;code&gt;X-Variant&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin Request Policy:&lt;/strong&gt; Cookies -&amp;gt; Include (or whitelist &lt;code&gt;X-Variant&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If missed, your logic silently defaults to &lt;code&gt;variant = 'control'&lt;/code&gt;, and your A/B test will appear broken.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Fidelity Gap: Why Testing is Critical
&lt;/h2&gt;

&lt;p&gt;The biggest barrier to adopting this pattern is what we call the &lt;strong&gt;Fidelity Gap&lt;/strong&gt;. Everything happens inside AWS infrastructure; your browser "lies" to you because it only sees the public URI.&lt;/p&gt;

&lt;p&gt;This leads to the classic (and painful) workflow: &lt;strong&gt;Deploy → Wait 20 minutes → Discover a 403 → Repeat.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing the Gap with Local Simulation
&lt;/h3&gt;

&lt;p&gt;To eliminate this blind spot, we can simulate the environment locally using &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/cloudfrontize" rel="noopener noreferrer"&gt;CloudFrontize&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Mock the S3 Origin
&lt;/h4&gt;

&lt;p&gt;Recreate your production structure in a local &lt;code&gt;/public&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/public
  ├── index.html
  └── variants/
      └── B/
          └── index.html

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Run the CloudFrontize simulator
&lt;/h4&gt;

&lt;p&gt;Emulate Lambda@Edge behavior locally with the &lt;code&gt;--debug&lt;/code&gt; flag to see the "Invisible" rewrite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cloudfrontize ./public &lt;span class="nt"&gt;--edge&lt;/span&gt; ./ab-testing.js &lt;span class="nt"&gt;--debug&lt;/span&gt; 

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Verify the Invisible Rewrite
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;http://localhost:3000/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the variant cookie in the browser console:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Variant=B&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What you should see in the terminal:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[origin-request] Original URI: /
[Debug] Rewriting URI: / -&amp;gt; /variants/B/index.html

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

&lt;/div&gt;



&lt;p&gt;Your browser still shows &lt;code&gt;/&lt;/code&gt;, but the content has changed. &lt;strong&gt;The Shadow Origin Pattern is working.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Professional Gotchas (Hard Lessons)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Environment Variables:&lt;/strong&gt; Lambda@Edge does not support &lt;code&gt;process.env&lt;/code&gt;. Your function must be self-contained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The 40KB Limit:&lt;/strong&gt; Large cookies can break your function unexpectedly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Invalidation:&lt;/strong&gt; Invalidating &lt;code&gt;/shop&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; invalidate &lt;code&gt;/variants/B/shop&lt;/code&gt;. You must invalidate both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regex Latency:&lt;/strong&gt; On high-traffic sites, complex regex adds latency. Prefer simple string operations.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧾 Summary
&lt;/h2&gt;

&lt;p&gt;High-performance edge architectures require discipline: keep the cache key clean and move logic behind the cache layer. By applying the &lt;strong&gt;Shadow Origin Pattern&lt;/strong&gt; and validating it locally with &lt;strong&gt;CloudFrontize&lt;/strong&gt;, you eliminate the deployment "black box" and gain full control over your edge behavior.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Next Step:&lt;/strong&gt; Are you ready to bridge the fidelity gap? Check out the &lt;a href="https://github.com/felipecarrillo100/cloudfrontize" rel="noopener noreferrer"&gt;CloudFrontize GitHub Repository&lt;/a&gt; for more edge patterns.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudfront</category>
      <category>devops</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Why is my CDN slow? Bypassing the 10MB Compression Limit on AWS CloudFront</title>
      <dc:creator>felipecarrillo100</dc:creator>
      <pubDate>Thu, 05 Mar 2026 23:19:35 +0000</pubDate>
      <link>https://dev.to/felipecarrillo100/why-is-my-cdn-slow-bypassing-the-10mb-compression-limit-on-aws-cloudfront-1okn</link>
      <guid>https://dev.to/felipecarrillo100/why-is-my-cdn-slow-bypassing-the-10mb-compression-limit-on-aws-cloudfront-1okn</guid>
      <description>&lt;h3&gt;
  
  
  The "Silent" Performance Killer
&lt;/h3&gt;

&lt;p&gt;You’ve deployed your data-heavy app to AWS CloudFront. You checked the "Compress Objects Automatically" box. You assume your 12MB GeoJSON or a 15MB JavaScript module is being zipped down to a manageable size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It isn't.&lt;/strong&gt; AWS CloudFront has a strict, hard-coded &lt;strong&gt;10MB limit&lt;/strong&gt; for automatic compression. If your file is 10.1MB, CloudFront serves the full-fat, uncompressed version. While you're testing on high-speed office Wi-Fi, your users on 4G/LTE suffer waiting 20 seconds or more for the app to load, and your Lighthouse scores are in the basement.&lt;/p&gt;

&lt;p&gt;To fix this, you have to take matters into your own hands: &lt;strong&gt;Pre-compress your assets and use Lambda@Edge to serve them.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠️ Step 1: Pre-Compressing the "Monsters"
&lt;/h3&gt;

&lt;p&gt;Since CloudFront won't touch files over 10MB, we compress them ourselves. We can do this manually but it is much more optimal if we do the work at build time.&lt;/p&gt;

&lt;p&gt;Using Vite, we can generate high-efficiency compression (Gzip and Brotli) for only the files that exceed that 10MB threshold. We can target any asset type: js,css, json, geojson, etc&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;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&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;span class="nx"&gt;otherStuff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Pass 1: Gzip&lt;/span&gt;
        &lt;span class="nf"&gt;viteCompression&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gzip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.gz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;js|mjs|json|css|html|geojson&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// ONLY compress files that CloudFront will refuse to touch (&amp;gt;10MB)&lt;/span&gt;
            &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10485760&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="c1"&gt;// Pass 2: Brotli&lt;/span&gt;
        &lt;span class="nf"&gt;viteCompression&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brotliCompress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.br&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;js|mjs|json|css|html|geojson&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// SAME threshold: 10MB&lt;/span&gt;
            &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10485760&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;publicDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&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;After building, your &lt;code&gt;./dist&lt;/code&gt; folder contains both the original asset plus the tiny &lt;code&gt;.br&lt;/code&gt; and &lt;code&gt;.gz&lt;/code&gt; versions of any file larger than 10MB, these are typically 7 to 10 times smaller.&lt;/p&gt;




&lt;h3&gt;
  
  
  ⚡ Step 2: The Logic (Lambda@Edge)
&lt;/h3&gt;

&lt;p&gt;AWS Cloudfront will not take the compressed files automatically. We need configure the logic using a Lambda@Edge function.&lt;/p&gt;

&lt;p&gt;Think of this as a "Traffic Controller" at the edge. Its job is to check if the browser supports high-efficiency compression and swap the file path of the large asset(s) &lt;code&gt;NYBuildings.geojson&lt;/code&gt; for its compressed version before it reaches the origin.&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This line tells the simulator to run this on 'origin-request'. Remove this line before deploying to AWS&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hookType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;origin-request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;cf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&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;headers&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;const&lt;/span&gt; &lt;span class="nx"&gt;uri&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;uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Targeted Match: Define a match pattern for the pre-compressed files&lt;/span&gt;
    &lt;span class="c1"&gt;// This example ONLY rewrites NYBuildings.geojson &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;uri&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/NYBuildings.geojson&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aeHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accept-encoding&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;acceptEncoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aeHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;aeHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;aeHeader&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Priority: Brotli (.br) &amp;gt; Gzip (.gz)&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;acceptEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;br&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.br&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;else&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;acceptEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gzip&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.gz&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;// Log the rewrite for CloudWatch debugging&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Lambda@Edge] Rewriting &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="p"&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;uri&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="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// All other files (JS, CSS, etc.) pass through normally.&lt;/span&gt;
    &lt;span class="c1"&gt;// CloudFront will use its "Automatic Compression" for them if enabled.&lt;/span&gt;
    &lt;span class="nf"&gt;callback&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="nx"&gt;request&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;
  
  
  🛠️ Step 3: Test the solution before deploying to AWS
&lt;/h3&gt;

&lt;p&gt;Developing Lambda@Edge is notoriously frustrating. Usually, every small change requires a full AWS deployment and &lt;strong&gt;15 minutes&lt;/strong&gt; of waiting for global propagation just to see if your code works. If you have a typo, you get a &lt;strong&gt;502 Bad Gateway&lt;/strong&gt; and no explanation.&lt;/p&gt;

&lt;p&gt;Rather than running your development code in an AWS environment—where every error costs time and money—you can run and debug your Lambda@Edge code directly on your PC using a simulator.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/cloudfrontize" rel="noopener noreferrer"&gt;CloudFrontize&lt;/a&gt;&lt;/strong&gt; changes the game. It is a local simulator that creates a high-fidelity AWS Edge environment on your machine. You don't even need an AWS account to start developing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify your logic instantly:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cloudfrontize ./dist &lt;span class="nt"&gt;--edge&lt;/span&gt; ./lambdaCompress.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant Feedback:&lt;/strong&gt; Refresh your browser and see the 12MB file instantly shrink to 1.3MB in the Network Tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch Errors Early:&lt;/strong&gt; CloudFrontize enforces strict AWS limits (like the 40KB body limit) locally. If your code is going to crash in production, it crashes in your terminal first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;cloudfrontize&lt;/code&gt; simulator acts as a static file server with &lt;code&gt;edge super powers&lt;/code&gt;. Your files at &lt;code&gt;./dist&lt;/code&gt; are served by default to port 3000. Open your browser at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your browser, inspect the network panel. You will see that the large geojson file is serve compressed in brotli format.&lt;/p&gt;

&lt;p&gt;You can also verify the compression and size using &lt;code&gt;curl&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;curl &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept-Encoding: br"&lt;/span&gt; http://localhost:3000/NYBuildings.geojson
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the encoding is br and the size is only 1316586 (1.3MB).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;content-encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;br&lt;/span&gt;
&lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost:3000&lt;/span&gt;
&lt;span class="na"&gt;user-agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl/8.13.0&lt;/span&gt;
&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;*/*&lt;/span&gt;
&lt;span class="na"&gt;accept-encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;br&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1316586&lt;/span&gt;
&lt;span class="na"&gt;Content-Disposition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inline; filename="NYBuildings.geojson.br"&lt;/span&gt;
&lt;span class="na"&gt;Accept-Ranges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bytes&lt;/span&gt;
&lt;span class="na"&gt;ETag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"0adb23e9ab344696b54737fe4e4bfa430f2ddf3c"&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;*&lt;/span&gt;
&lt;span class="na"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Thu, 05 Mar 2026 23:10:32 GMT&lt;/span&gt;
&lt;span class="na"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;keep-alive&lt;/span&gt;
&lt;span class="na"&gt;Keep-Alive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;timeout=5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🚀 Step 4: Confident Deployment
&lt;/h3&gt;

&lt;p&gt;Once your &lt;code&gt;cloudfrontize&lt;/code&gt; simulation proves the logic is bulletproof, you can deploy to your live AWS distribution using the standard AWS console.&lt;/p&gt;




&lt;h3&gt;
  
  
  💎 Step 5: The "Pro" Solution – CloudFront Functions (CFF)
&lt;/h3&gt;

&lt;p&gt;For conditional rewrites, CloudFront Functions (CFF) are superior to Lambda@Edge in both speed and economy. CFF is specifically designed for lightweight tasks, delivering results faster while being 6x cheaper. Unless your logic requires complex external integrations or body access, CFF is the more efficient choice.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Logic
&lt;/h4&gt;

&lt;p&gt;Save the following snippet. Note that we use strictly JavaScript ES 5.1 syntax (using var and indexOf) to comply with the restricted CloudFront Functions runtime. Using modern ES6+ features like const or .includes() will cause the function to fail in production.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;uri&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;uri&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;uri&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/NYBuildings.geojson&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;headers&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;var&lt;/span&gt; &lt;span class="nx"&gt;acceptEncoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accept-encoding&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="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accept-encoding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&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;acceptEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;br&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.br&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;else&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;acceptEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gzip&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.gz&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&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;p&gt;To run this in the 'cloudfrontize' , save the code as &lt;code&gt;viewer-request-compression.js&lt;/code&gt;. The &lt;code&gt;viewer-request&lt;/code&gt; prefix is mandatory; it tells the simulator exactly which CFF trigger point to execute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; cloudfrontize ./dist &lt;span class="nt"&gt;--cff&lt;/span&gt; ./viewer-request-compression.js &lt;span class="nt"&gt;--strict&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  👉 Serving Precompressed Assets Correctly (Important!!)
&lt;/h3&gt;

&lt;p&gt;The example above works “as-is” for JSON files, since browsers are generally less strict when handling JSON responses. However, particular care is required when serving assets such as &lt;code&gt;.js&lt;/code&gt; and &lt;code&gt;.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Modern web browsers rely on correct HTTP headers to properly interpret and execute resources. If you serve a compressed file (for example, &lt;code&gt;file.js.br&lt;/code&gt;) as &lt;code&gt;file.js&lt;/code&gt; without the appropriate headers, the browser will fail to process it correctly..&lt;/p&gt;

&lt;p&gt;This is not due to the compression itself, but because the browser is unaware of the encoding or receives an incorrect content type.&lt;/p&gt;

&lt;p&gt;When using &lt;strong&gt;CloudFront Functions (CFF)&lt;/strong&gt; and &lt;strong&gt;Lambda@Edge Functions&lt;/strong&gt;, keep in mind that you can modify request and response headers, but you must ensure that compressed assets are returned with the correct metadata or browser will discard them.&lt;/p&gt;

&lt;p&gt;You can configure the required headers in multiple places:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At the S3 bucket level by setting object metadata&lt;/li&gt;
&lt;li&gt;In a Lambda@Edge function (response phase)&lt;/li&gt;
&lt;li&gt;In a CloudFront Function (viewer-response) &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For JavaScript files compressed using brotli, ensure the following headers are present:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Encoding: br
Content-Type: application/javascript
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or if you use gzip compression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Encoding: gz
Content-Type: application/javascript
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Failing to set these headers correctly will prevent the browser from interpreting the file as valid JavaScript/CSS. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution&lt;/strong&gt;: Brotli requires a secure context (HTTPS or localhost); always offer gzip as a fallback.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  📊 The Results
&lt;/h3&gt;

&lt;p&gt;By bypassing the 10MB limit and using a local-first development workflow, the numbers speak for themselves:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;CloudFront (Uncompressed)&lt;/th&gt;
&lt;th&gt;Lambda@Edge + brotli pre-compression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Payload Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12.15 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.31 MB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bandwidth Saving&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~89%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  🚀 Try it Yourself
&lt;/h4&gt;

&lt;p&gt;I’ve put together a complete repository featuring a &lt;strong&gt;12MB NYC Buildings&lt;/strong&gt; dataset in GeoJSON format. Using the Brotli pre-compression strategy, we shrink this file to just &lt;strong&gt;1.3MB&lt;/strong&gt; during the build.&lt;/p&gt;

&lt;p&gt;The repository includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vite Setup:&lt;/strong&gt; Pre-configured with the compression plugin and the 10MB threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Traffic Controller":&lt;/strong&gt; The complete Lambda@Edge function for the URI rewrite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-Click Simulator:&lt;/strong&gt; Everything you need to see the 90% size reduction in action in seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/felipecarrillo100/vite-brotli-cloudfront-sample" rel="noopener noreferrer"&gt;GitHub: vite-brotli-cloudfront-sample&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>aws</category>
      <category>cloudfront</category>
      <category>performance</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
