# First look: static asset caching

**URL:** <https://community.fly.io/t/first-look-static-asset-caching/1375>\
**Category:** Phoenix\
**Created:** [May 5, 2021, 6:17pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375 "2021-05-05T18:17:40Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kurt](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/kurt/32/43757_2.png) [@kurt](https://community.fly.io/u/kurt)\
**Post date:** [May 5, 2021, 6:17pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/1 "2021-05-05T18:17:40Z")

</div>

One comment we keep getting from people building _super_ interesting fullstack apps is: “I don’t want to have to deal with a CDN when I deploy”.

[Fly.io](http://Fly.io) isn’t a CDN, but we do have some CDN-like infrastructure that we can do fun things with. Today’s fun thing is `[[statics]]` in `fly.toml`. Add a config section to your app like this:

```auto
[[statics]]
guest_path = "/app/web/dist"
url_prefix = "/static"

```

When you deploy, we’ll pull `/app/web/dist` out of your packaged app, then serve requests that to `https://<app>/static` from caches on our edge servers. You don’t have to worry about cache purging or expiration or anything, each deploy just does the right thing. _And_ we keep a few versions around so you don’t get blank pages mid deploy, people who request outdated static URLs will get what they expect.

Requests to static files fall through to your app if they don’t exist, so you can even use this for `/index.html` and have your app servers handle `/graphql`.

This is not a replacement for Netlify! And if you really need a CDN, it’s not going to solve all your problems (but, like, most people don’t need CDNs). It’s very specifically designed for assets that get deployed alongside full stack Phoenix/Rails/Laravel/Django apps.

---

<div class="post-metadata">

**Author:** ![thomas](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/thomas/32/40188_2.png) [@thomas](https://community.fly.io/u/thomas)\
**Post date:** [May 5, 2021, 7:50pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/2 "2021-05-05T19:50:34Z")

</div>

Some things to know going in:

- There are likely to be some rough edges, and when you run into them, please let us know and we’ll hunt them down.

- Static assets are currently tied to instances that you deploy (we fish them out of the container image you deploy, and serve them off the worker host you’re deployed on). This is less-than-optimal if what you’re looking for is mostly using us as a static asset host, but solves the problem of “I don’t want to have to roll a container image with both my app server _and_ an nginx or something”.

If you could get mileage out of something more ambitious than this, _please tell us!_. We’re situated to expand on this, but prioritizing what we’re working on based on what y’all ask for.

Regardless, if you kick the tires on this, thank you!

---

<div class="post-metadata">

**Author:** ![maciejgryka](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/maciejgryka/32/624_2.png) [@maciejgryka](https://community.fly.io/u/maciejgryka)\
**Post date:** [May 5, 2021, 8:28pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/3 "2021-05-05T20:28:34Z")

</div>

So I’ve just tried this out - I think it all works, as in nothing is broken, but I’m not really sure `[[statics]]` had any effect. How can I tell?

---

<div class="post-metadata">

**Author:** ![thomas](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/thomas/32/40188_2.png) [@thomas](https://community.fly.io/u/thomas)\
**Post date:** [May 5, 2021, 8:46pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/4 "2021-05-05T20:46:18Z")

</div>

We should add a distinguishing header here; I’m on that. In the meantime: I just test by serving assets that my app server doesn’t serve itself. 🙂

---

<div class="post-metadata">

**Author:** ![mikeb](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/mikeb/32/656_2.png) [@mikeb](https://community.fly.io/u/mikeb)\
**Post date:** [May 5, 2021, 10:24pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/5 "2021-05-05T22:24:36Z")

</div>

I could use something more ambitious if you are thinking about it.

Currently about to move some Google cloud functions to [fly.io](http://fly.io). They generate images based on parameters in the url (along the lines of imgix, [imagekit.io](http://imagekit.io) etc). At the moment they are fronted by google’s CDN via the load balancer configuration.

Once I moved them to fly, I was planning to front with AWS cloudfront or possibly look at using nginx/varnish inside fly.

End goal would be a cache layer that honors the cache header from the origin , and caches at the edge (for at most a day).

Long term it would be good to get metrics/bandwidth usage information from the cache layer, but not an initial requirement.

---

<div class="post-metadata">

**Author:** ![jordangens](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/jordangens/32/676_2.png) [@jordangens](https://community.fly.io/u/jordangens)\
**Post date:** [May 8, 2021, 5:28pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/6 "2021-05-08T17:28:58Z")

</div>

This looks neat, tried it and it works as expected!

One thing I noticed is that there don’t seem to be any cache-control headers in the response.

---

<div class="post-metadata">

**Author:** ![kurt](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/kurt/32/43757_2.png) [@kurt](https://community.fly.io/u/kurt)\
**Post date:** [May 9, 2021, 5:45pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/7 "2021-05-09T17:45:16Z")

</div>

That’s a good point. We should probably send basic revalidate headers.

---

<div class="post-metadata">

**Author:** ![jsierles](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/jsierles/32/595_2.png) [@jsierles](https://community.fly.io/u/jsierles)\
**Post date:** [May 9, 2021, 9:53pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/8 "2021-05-09T21:53:49Z")

</div>

I second the motion for obeying cache control headers from the origin.

In particular, I have found Fastly’s support for the [Surrogate-Control](https://datatracker.ietf.org/doc/html/draft-nottingham-surrogates-00#section-3.6.2) header useful avoiding something getting stuck in browser cache forever. Maybe not applicable to the ‘js/css assets’ use case, though.

Another ‘ambitious’ thing: I’ve seen lots of apps using a passthrough CDN merely to split requests out by path to different origins. So for example, `mayonnaise.app` would route to a static marketing site, but `mayonnaise.app/joshua` would route to a web application.

Being able to do this and get asset caching without using a CDN product would be a win!

This is related to my other post about [path-based routing](https://community.fly.io/t/path-based-http-routing-to-instance-groups-of-a-single-deployment/1240). Only here, we would be routing organization-wide instead of between components within an app.

---

<div class="post-metadata">

**Author:** ![OldhamMade](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/oldhammade/32/40954_2.png) [@OldhamMade](https://community.fly.io/u/OldhamMade)\
**Post date:** [May 15, 2021, 12:20pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/9 "2021-05-15T12:20:10Z")

</div>

How much of a performance penalty would there be to set `url_prefix = "/"` for a dynamic app?

---

<div class="post-metadata">

**Author:** ![kurt](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/kurt/32/43757_2.png) [@kurt](https://community.fly.io/u/kurt)\
**Post date:** [May 16, 2021, 5:17pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/10 "2021-05-16T17:17:41Z")

</div>

It should be negligible. Static files looks are sub millisecond.

---

<div class="post-metadata">

**Author:** ![ajbouh](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/ajbouh/32/1771_2.png) [@ajbouh](https://community.fly.io/u/ajbouh)\
**Post date:** [May 19, 2021, 5:37pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/11 "2021-05-19T17:37:11Z")

</div>

Is it possible to use wildcards or route patterns in `url_prefix`?

Suppose in my application I have URLs that look like this:

- `/jobs/34234523/graphql` GraphQL API to query a specific job
- `/jobs/34234523/index.html` UI that issues API calls to the the `graphql` endpoint

I’d prefer to have a `[[statics]]` block that looks like:

```auto
[[statics]]
guest_path = "/app/web/dist"
url_prefix = "/jobs/*/"

```

This way users can just navigate to `/jobs/34234523` and see a UI specific to that job.

This is a pattern I’ve adopted in a number of my projects. It strikes a balance between:

- clean URLs,
- simple to write UI,
- and reasonably decoupled backend API

---

<div class="post-metadata">

**Author:** ![thomas](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/thomas/32/40188_2.png) [@thomas](https://community.fly.io/u/thomas)\
**Post date:** [May 19, 2021, 10:16pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/12 "2021-05-19T22:16:40Z")

</div>

It’s not currently possible, but it’s a reasonable request. I could also just use regular expression matching here, I guess?

---

<div class="post-metadata">

**Author:** ![ajbouh](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/ajbouh/32/1771_2.png) [@ajbouh](https://community.fly.io/u/ajbouh)\
**Post date:** [May 19, 2021, 10:21pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/13 "2021-05-19T22:21:15Z")

</div>

Yeah anything along those lines would be great. I think this idea of “interpret the URL in javascript after page load” is a fairly powerful one.

I’ve used it with Netlify via their routing/rewriting/proxying rules: [Rewrites and proxies | Netlify Docs](https://docs.netlify.com/routing/redirects/rewrites-proxies/)

---

<div class="post-metadata">

**Author:** ![thomas](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/thomas/32/40188_2.png) [@thomas](https://community.fly.io/u/thomas)\
**Post date:** [May 19, 2021, 10:35pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/14 "2021-05-19T22:35:08Z")

</div>

I think this is not at all hard for us to implement, but don’t hold me to that until I deploy the official ⚡ 🍥 **we’re doing this right now** 🍥 ⚡ declaration. I’m already working in this code today, so I might be able to get this on my docket relatively quickly.

---

<div class="post-metadata">

**Author:** ![OldhamMade](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/oldhammade/32/40954_2.png) [@OldhamMade](https://community.fly.io/u/OldhamMade)\
**Post date:** [May 20, 2021, 6:43pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/15 "2021-05-20T18:43:33Z")

</div>

I’ve configured with:

```auto
[[statics]]
  guest_path = "/app/static/"
  url_prefix = "/"

```

But I don’t think static files are being served from the cache; I’m not seeing anything in the `HTTP CACHE RATIOS` section in Metrics. Should hits be logged there?

@thomas Do cache hits identify themselves with a response header?

---

<div class="post-metadata">

**Author:** ![thomas](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/thomas/32/40188_2.png) [@thomas](https://community.fly.io/u/thomas)\
**Post date:** [May 20, 2021, 6:56pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/16 "2021-05-20T18:56:52Z")

</div>

They don’t right now! At present, the only thing this feature really does for you is keep you from needing to run a static asset server in your container; we put it together because that seemed easier than talking people through writing multi-process Dockerfiles.

But that’s changing as we speak! I’ll have more to talk about w/r/t caching and tracking in the next couple days.

(If you’ve got an app that relies on `statics` to deliver content, and isn’t functioning, that’s news, and definitely let us know.)

---

<div class="post-metadata">

**Author:** ![kurt](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/kurt/32/43757_2.png) [@kurt](https://community.fly.io/u/kurt)\
**Post date:** [May 20, 2021, 7:09pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/17 "2021-05-20T19:09:03Z")

</div>

I was wrong about the caching! Look at me creating scope creep.

---

<div class="post-metadata">

**Author:** ![aswinmohanme](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/aswinmohanme/32/1921_2.png) [@aswinmohanme](https://community.fly.io/u/aswinmohanme)\
**Post date:** [May 28, 2021, 7:23pm UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/18 "2021-05-28T19:23:07Z")

</div>

How do we make this work on a Phoenix App ? I can’t find the static file looking in /app

---

<div class="post-metadata">

**Author:** ![rushsteve12](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rushsteve12/32/764_2.png) [@rushsteve12](https://community.fly.io/u/rushsteve12)\
**Post date:** [June 1, 2021, 12:59am UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/19 "2021-06-01T00:59:50Z")

</div>

If you’re using an Elixir Release based deployment like the one in the guide, then static assets are stored in `/app/lib/[your-app]-[version]/priv/static` in folders which would have to be listed separately.

---

<div class="post-metadata">

**Author:** ![OldhamMade](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/oldhammade/32/40954_2.png) [@OldhamMade](https://community.fly.io/u/OldhamMade)\
**Post date:** [June 16, 2021, 10:57am UTC](https://community.fly.io/t/first-look-static-asset-caching/1375/23 "2021-06-16T10:57:55Z")

</div>

> [@OldhamMade](#):
>
> I’m not seeing anything in the `HTTP CACHE RATIOS` section in Metrics. Should hits be logged there?

Hey @fly guys, I didn’t really get an answer to this question, so wanted to give it a bump.

Right now, the `HTTP CACHE RATIOS` metrics box across all my apps (and accounts) show `No data available` despite most of them using the new Statics config.

Is that to be expected? If not, what _should_ be showing there?

[Next page](https://community.fly.io/t/first-look-static-asset-caching/1375.md?page=2)
