Tradeoffs: CDN vs local images
Tags: reactnative, cdn
Published: 2023-11-11 02:40:30

![If it works, don't touch it!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d21cjxmiiv1wb20n04io.gif)

The past week I tried to make a conscious decision to spend 30 minutes a day thinking about important but not urgent problems, one of the things that came up was whether CDN was really a valuable long-term solution...

| Local images | CDN-hosted images|
|----|----|
| ![Local images](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aodmmkogifzysu3vh5fo.jpeg) | ![CDN-hosted images](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67w3eoya1ic6v0udrzev.jpeg) |


## Summary of Differences

| **Criteria**| **Local images**| **CDN-hosted images**|
|:-----------------|:-----------------------------------------------------------------------|:----------------------------|
| **APP size**        | large                                                                 | ✅ small                      |
| **Maintainability** | ✅ simple                                                                | extra need to maintain CDN |
| **Responsiveness**  | if Business Team decides to change image, have to upgrade APP version | ✅ remote changes possible    |
| **Speed**           | ✅ fastest                                                               | need time for API call     |
| **Cost ($$)**       | ✅ no extra cost, build and deploy                                       | cost of storing on CDN     |

It seems quite an even split between the two solutions, but given our default solution was Local-stored images, I wonder if I could find any good reason to migrate to CDN:
1. Could the CDN cost be negligible enough to be as good as storing in-app?
2. Could we make the CDN API call time be fast enough to match the in-app solution, or perhaps even if it is slower, can it meet our Service-Level Agreement (SLA) in page load speed?

And a question just to balance our perspective to support in-app solution:
1. How much space do we save by moving to CDN? Or exactly what's the value gained?

### Caveats
The evaluations here are highly contextual:
* what I say is good for APP might not hold true for webpages,
* our APP is lightweight, an app that is heavy on image quality or livestreaming will be quite different

## 1. What is the exact cost of hosting on CDN?
I found a [pretty useful page](https://www.linkedin.com/advice/0/what-costs-using-content-delivery-network-cdn-ed0xc) on linkedin that summarises this. Essentially, there are 3(+1) subscription models:
1. Pay-as-you-go (expensive if high and unstable traffic)
2. Subscription (stable, but expensive if low & fluctuating traffic)
3. Hybrid (confusing to manage)
4. Free Tier (great if use case small enough!)

Factors that matter:
* Data Transfer -- how many TBs?
* Number of Requests
* Content Type -- static images vs dynamic resource like database
* Location -- North America has higher supply of CDNs, so cheaper there than Asia

Based on the above, I tried to look at a few providers:
1. Amazon CloudFront
2. Google CDN
3. Akamai CDN
4. CloudFlare CDN

But really stopped at the first one lol. It had a free-tier that actually serves our use-case perfectly.

![AWS Free Tier](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0zulhyim3aw341wapgq.png)

This, considering we had ~100,000 active users that access the APP on average 5 times a week. Assuming they traverse quarter of the APP, that's quarter of 8MB of images loaded, which is 
```javascript
2 MB * 500,000 = 1 TB
```
Worst case though, if we double that load to 2 TB, it seems to cost only US$87 a month to host a CDN for such loads in USA on Amazon CloudFront. 

P.S Actually since we were a Singapore-based APP for Singapore users, and we had already been hosting our own internal databases, maybe it made more sense to use internal systems to host it. But maybe let's leave that for the 3rd part of this series. As to why this makes sense, let's answer in context of the question below

## 2. What is our Service-Level Agreement (SLA) in page load speed?
I'd figure since we are a banking app (as compared to a high-frequency trading app), we would actually have more leeway, so speed isn't much of an issue. Remote-hosted images instead of local in-app was okay.

Plus there are great engineering ideas from Twitter and some other companies:
* load images in large pixels (low resolution), and make continuous requests to retrieve and increasingly render higher resolution images
* hot loading / caching to retrieve the images while app is in the background
* Promise.all() to get images while you get other page data to run requests in parallel

## 3. Exactly how much space does images take up in the APP?
Here's a [stackoverflow discussion](https://stackoverflow.com/questions/42282252/image-sizes-for-android-and-ios-in-react-native) on why images have `@1.5x`, `@2x` and `@3x`

And since we have 8 - 10 MB of images, honestly moving images to CDN only saves 4 - 5 seconds to download the app.

## Conclusion
While a beautiful solution is hosting images both on our cheap internal database and Amazon CloudFront to remove all images from the APP itself, the value seems marginal of about 4 - 5 seconds less to download the APP. Considering app download is a one-time action, likely business impact is little.

Perhaps it makes more sense to stop at Part 1 of this series' solution to reduce duplicate images.

However, for learning sake, let's continue to part 3 on understanding how we can host these images from a local database!