DEV Community

Cover image for Why is my CDN slow? Bypassing the 10MB Compression Limit on AWS CloudFront
felipecarrillo100
felipecarrillo100

Posted on

Why is my CDN slow? Bypassing the 10MB Compression Limit on AWS CloudFront

The "Silent" Performance Killer

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.

It isn't. AWS CloudFront has a strict, hard-coded 10MB limit 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.

To fix this, you have to take matters into your own hands: Pre-compress your assets and use Lambda@Edge to serve them.


🛠️ Step 1: Pre-Compressing the "Monsters"

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.

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

export default defineConfig({
    plugins: [
        ...otherStuff,
        // Pass 1: Gzip
        viteCompression({
            algorithm: 'gzip',
            ext: '.gz',
            filter: /\.(js|mjs|json|css|html|geojson)$/i,
            // ONLY compress files that CloudFront will refuse to touch (>10MB)
            threshold: 10485760,
            verbose: true
        }),
        // Pass 2: Brotli
        viteCompression({
            algorithm: 'brotliCompress',
            ext: '.br',
            filter: /\.(js|mjs|json|css|html|geojson)$/i,
            // SAME threshold: 10MB
            threshold: 10485760,
            verbose: true
        }),
    ],
    publicDir: 'public'
});
Enter fullscreen mode Exit fullscreen mode

After building, your ./dist folder contains both the original asset plus the tiny .br and .gz versions of any file larger than 10MB, these are typically 7 to 10 times smaller.


⚡ Step 2: The Logic (Lambda@Edge)

AWS Cloudfront will not take the compressed files automatically. We need configure the logic using a Lambda@Edge function.

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 for its compressed version before it reaches the origin.

'use strict';

// This line tells the simulator to run this on 'origin-request'. Remove it before deploying to AWS
exports.hookType = 'origin-request';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    const uri = request.uri;

    // Modified Regex: Added 'geojson' to the targeted file types
    if (uri.match(/\.(js|css|json|geojson)$/)) {
        const aeHeader = headers['accept-encoding'];
        const acceptEncoding = (aeHeader && aeHeader.length > 0) ? aeHeader[0].value : '';

        // Priority: Brotli (.br) > Gzip (.gz)
        if (acceptEncoding.includes('br')) {
            request.uri += '.br';
        } else if (acceptEncoding.includes('gzip')) {
            request.uri += '.gz';
        }

        // Log the rewrite for CloudWatch debugging
        console.log(`Rewriting ${uri} to ${request.uri}`);
    }

    callback(null, request);
};
Enter fullscreen mode Exit fullscreen mode

🛠️ Step 3: Test the solution before deploying to AWS

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

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.

This is where CloudFrontize 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.

Verify your logic instantly:

cloudfrontize ./dist --edge ./lambdaCompress.js -d -C
Enter fullscreen mode Exit fullscreen mode
  • Instant Feedback: Refresh your browser and see the 12MB file instantly shrink to 1.3MB in the Network Tab.
  • Catch Errors Early: 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.

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

http://localhost:3000/
Enter fullscreen mode Exit fullscreen mode

In your browser, inspect the network panel. You will see that the large geojson file is serve compressed in brotli format.

You can also verify the compression and size using curl

curl -I -H "Accept-Encoding: br" http://localhost:3000/NYBuildings.geojson
Enter fullscreen mode Exit fullscreen mode

Notice the encoding is br and the size is only 1316586 (1.3MB).

HTTP/1.1 200 OK
content-encoding: br
host: localhost:3000
user-agent: curl/8.13.0
accept: */*
accept-encoding: br
Content-Length: 1316586
Content-Disposition: inline; filename="NYBuildings.geojson.br"
Accept-Ranges: bytes
ETag: "0adb23e9ab344696b54737fe4e4bfa430f2ddf3c"
Access-Control-Allow-Origin: *
Date: Thu, 05 Mar 2026 23:10:32 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Enter fullscreen mode Exit fullscreen mode

🚀 Step 4: Confident Deployment

Once your cloudfrontize simulation proves the logic is bulletproof, you can deploy to your live AWS distribution using the standard AWS console.


📊 The Results

By bypassing the 10MB limit and using a local-first development workflow, the numbers speak for themselves:

Metric CloudFront (Uncompressed) Lambda@Edge + brotli pre-compression
Payload Size 12.15 MB 1.31 MB
Bandwidth Saving 0% ~89%

🚀 Try it Yourself

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

The repository includes:

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

GitHub: vite-brotli-cloudfront-sample


Top comments (0)