EAS Update asset limit -- is there any workaround?

I’m trying to use EAS update but due to the nature of my app (a game) I have lots of assets. EAS update errors with “During EAS Update Preview, we are limiting uploads to 600 assets per publish. You have attempted to upload 787 assets.”

Is there any workaround for this? Maybe a way to exclude assets from EAS update that I’m certain are already present in all available app bundles?

We limit how many assets a single update can have because of the impact on user experience and server load. Downloading hundreds of assets over a mobile data plan is slow and expensive for end users. We’ve found that in practice, high asset counts are often caused by inefficient libraries or bundler (Metro) configurations. Look for these in your app.

One pattern we’ve seen is that some libraries that include packs of fonts or icons often have an entry point file that imports all the fonts or all the icons: export * from './font-1'; export * from './font-2'; ... export * from './font-100';. When your project imports the entire library (import { Font1 } from 'example-font-package'), the bundler pulls in all 100 fonts. Font libraries also tend to include both a TTF and JSON metadata file for each font, meaning that 200 assets would be included in this example even though your app uses just one font.

The fix is to import just what you need. Several libraries support writing import Font1 from 'example-font-package/font-1. This way your dependency graph would include just the files you actually use. This also optimizes the size of your app that is submitted to the stores since they would exclude the 99 other fonts you don’t use.

The second issue we’ve seen is that the Metro bundler will include all JSON files twice: once as an asset and once in your JS bundle. In the next upcoming SDK release (SDK 45) we are changing the default configuration to include JSON just once in your JS bundle, with an escape hatch for apps that need to include duplicate JSON data for unanticipated reasons. As mentioned above, this affects font and icon packages that often have one JSON file per font/icon. I don’t know the specifics off the top of my head but you can use assetExts in metro.config.js to exclude json files.

Longer term, we might start to think about ways to denote which data is part of your app’s runtime and isn’t part of an update. Due to how the bundler stack works today, all JS + other assets are bundled up together. It would be better to be more like browsers or Node.js, which include JS and other assets alongside native code baked into their runtimes. For Expo, the analogue would be to treat chosen libraries as part of the native app runtime, and whether those libraries contains native code, JS, or other assets, their entire contents would be baked into the native app and be excluded from live updates (Expo Updates). Our roadmap is full for the foreseeable future but we might consider an escape hatch to exclude specified assets from updates in the meantime, with the caveat that there are hard-to-anticipate ways this could break your app.

Our app is a game, we actually do have 700+ image assets, there are no bundler issues or unnecessary imports.

The images generally don’t change after they’ve been deployed and we don’t frequently add or change more than a few images per update. Why does the EAS bundle process need to upload every asset? Essentially I need an option to tell the bundler “ignore these files, I guarantee they’re shipped with every binary that might get this update”.

Is there any workaround for this? We really do have that many assets but they mostly don’t change. An option to ignore some assets that I can guarantee will be in every binary would do the trick.

Hi - we don’t have a built-in workaround for this now. This is the first use case I’d say has a legitimate need for excluding assets, as opposed to the scenarios I described in an earlier post. An escape hatch is something we eventually want to provide.

The way EAS Update (expo export technically) gets the list of assets is from the Metro bundler, which finds all require() calls that reference an asset. I do not recommend this but if you hid the static require calls from Metro, in theory the assets they reference wouldn’t be included in the exported update.

We already actually do that for a lot of images as a performance improvement. We copy them to .xcassets on iOS and drawable on android before build then load them via the uri: specifier per the react-native docs on Images From Hybrid App’s Resources. We’ve found that loading “raw” images this way is much faster than loading via require() especially on Android where performance is generally much worse than iOS.

While we’re iterating on some image content however we load it via require() so that we can codepush updates. I’ll have to see if we can transfer more of the images into the binaries to get under the EAS limit for now. Using the classic expo publish mechanism seems to work for now as a workaround.

Hey @ide any update on this one? We’re still using expo publish but it seems that is deprecated with the new CLI. We need to find a solution to this since we can’t use EAS update until it’s resolved.

We slightly increased the asset limit to 700 I believe and have improved the reliability of uploading very large numbers of assets. We are targeting a hard limit a bit higher than this though fewer assets will usually be better for your users’ experiences and your bill if you use a lot of CDN bandwidth.

We aren’t actively working on embedded-only updates this moment but that will likely be the best solution for apps with a lot of assets that aren’t updated.

You can continue to use the classic updates service and expo-cli. We’ll give generous advance notice (more than a year) for when such a major migration to the modern updates protocol is required, whether you choose to use EAS Update or run your own server that implements the Expo Updates protocol. And we’ll keep improving parts of the migration path to EAS Update over time.

1 Like

Thanks for the reply! I got EAS update working for our app by moving more images to load from native so EAS update doesn’t pick them up.

One more question – we still have a lot of images (~500) that get picked up by EAS update. Does it force clients to download all of them images for any update? Or will it ignore unchanged files?

Hi evelant, the expo-updates module downloads only assets that it doesn’t have locally. You can confirm the behavior by intercepting the network traffic from your phone but you should see that your app fetches only new/changed assets.

For example, if you install your app from the store and launch it and there is a new update available that uses all the same images, you should see only two network requests: one to check for a new update (that is, a request for the update manifest) and one to get the new JS. Since your 500 images were embedded in the app from the store, they won’t be redownloaded.

Small caveat: we’ve seen apps re-fetch the React Navigation back arrow icons but haven’t prioritized looking into that since those icons are tiny and they are re-fetched just once, namely the first time an app gets an update after it is initially installed from the store. Afterwards the app will use the downloaded navigation icons.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.