HomeGuidesReferenceLearn
ArchiveExpo SnackDiscord and ForumsNewsletter

Assets

Learn about using static assets in your project, including images, videos, sounds, database files, and fonts.


Files such as images, videos, sounds, database files for SQLite, or fonts are considered static assets. They are not part of your project's JavaScript but are part of your app. These assets can be served locally from your project or remotely over the network.

Serve an asset locally

When an asset is stored in your project's file system, it can be embedded in your app binary at build time or loaded at runtime. You can import them like JavaScript modules using require or import statements.

For example, to render an image called example.png in App.js, you can directly use require to import the image from the project's assets/images directory and pass it to the <Image> component:

App.js
<Image source={require('./assets/images/example.png')} />

The bundler automatically provides a width and height for the images imported, as shown in the above example. For more information, see Static Image Resources.

Libraries such as expo-image and expo-file-system work similarly to the <Image> component with local assets.

How are assets served locally

Locally stored assets are served over HTTP in development. They are automatically bundled into your app binary at the build time for production apps and served from disk on a device.

Load an asset at build time

Note: The expo-asset config plugin is only available for SDK 51 and above. If you are using an older SDK, you can load a using the useAssets hook.

Install the expo-asset library and add the config plugin to the app config file. This plugin will embed the asset file in your native project.

app.json
{
  "plugins": [
    [
      "expo-asset",

      {
        "assets": ["./assets/images/example.png"]
      }
    ]
  ]
}

The assets option takes an array of one or more asset files or directory names to link the file to the native project. The path to each file is relative to the project's root.

When you create a new native build, you can import and use the asset in your project without using a require or an import statement.

For example, the example.png is linked by the above config plugin. You can directly import it into your component and use its resource name.

App.js
import { Image } from 'expo-image';
%%placeholder-start%%... %%placeholder-end%%

function App() {
  return <Image source="example" />;
}

The above example is quite concise. However, when a native API expects a specific file and its resource name, this method makes it convenient to integrate with that API and use the resource name directly.

For more information on supported file formats used with the config plugin, see Assets API reference.

Load an asset at runtime

Install the expo-asset library in your project. Once the installation step is complete, import the useAssets hook from the expo-asset library. The hook downloads and stores an asset locally, and after the asset is loaded, it returns a list of that asset's instances.

App.js
import { useAssets } from 'expo-asset';

export default function App() {
  const [assets, error] = useAssets([
    require('path/to/example-1.jpg'),
    require('path/to/example-2.png'),
  ]);

  return assets ? <Image source={assets[0]} /> : null;
}

Serve an asset remotely

When an asset is served remotely, it is not bundled into the app binary at build time. You can use the URL of the asset resource in your project if it is hosted remotely. For example, pass the URL to the <Image> component to render a remote image.

App.js
import { Image } from 'expo-image';
%%placeholder-start%%... %%placeholder-end%%

function App() {
  return (
    <Image source={{ uri: 'https://example.com/logo.png' }} style={{ width: 50, height: 50 }} />
  );
}

There is no guarantee about the availability of images served remotely using a web URL because an internet connection may not be available, or the asset might be removed.

Additionally, loading assets remotely also requires you to provide metadata about the asset. In this example, the bundler cannot retrieve the image's width and height, so you have to pass that explicitly to the <Image> component. If you don't, the image will default to 0px by 0px.

Manual optimization methods

Images

You can compress images using the following:

Some image optimizers are lossless. They re-encode your image to be smaller without any change or loss in the pixels displayed. When you need each pixel to be untouched from the original image, a lossless optimizer and a lossless image format like PNG are a good choice.

Other image optimizers are lossy. The optimized image differs from the original image. Often, lossy optimizers are more efficient because they discard visual information that reduces file size while making the image look nearly identical to humans. Tools like imagemagick can use comparison algorithms like SSIM to show how similar two images look. It's quite common for an optimized image that is over 95% similar to the original image to be far less than 95% of the original file size.

Fonts

See Wait for fonts to load in the Fonts guide for more information.

Other assets

For assets like GIFs or movies, or non-code and non-image assets, it's up to you to optimize and minify those assets.

Note: GIFs are a very inefficient format. Modern video codecs can produce significantly smaller file sizes with better quality.