This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

Expo MediaLibrary (legacy) iconExpo MediaLibrary (legacy)

A library that provides access to the device's media library.

Android
iOS
tvOS
Included in Expo Go
Recommended version:
~56.0.11

expo-media-library provides access to the user's media library, allowing them to access their existing images and videos from your app, as well as save new ones. You can also subscribe to any updates made to the user's media library.

Installation

Terminal
- npx expo install expo-media-library
- yarn expo install expo-media-library
- pnpm expo install expo-media-library
- bun expo install expo-media-library

If you are installing this in an existing React Native app, make sure to install expo in your project.

Configuration in app config

You can configure expo-media-library using its built-in config plugin if you use config plugins in your project (Continuous Native Generation (CNG)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library.

Example app.json with config plugin

{ "expo": { "plugins": [ [ "expo-media-library", { "photosPermission": "Allow $(PRODUCT_NAME) to access your photos.", "savePhotosPermission": "Allow $(PRODUCT_NAME) to save photos.", "isAccessMediaLocationEnabled": true, "granularPermissions": ["audio", "photo"] } ] ] } }

Configurable properties

NameDefaultDescription
photosPermission"Allow $(PRODUCT_NAME) to access your photos."
Only for: 
iOS

Sets the iOS NSPhotoLibraryUsageDescription permission message in Info.plist.

savePhotosPermission"Allow $(PRODUCT_NAME) to save photos."
Only for: 
iOS

Sets the iOS NSPhotoLibraryAddUsageDescription permission message in Info.plist.

preventAutomaticLimitedAccessAlertfalse
Only for: 
iOS

Prevents the automatic limited access alert from being shown when the user has limited access to the photo library. Useful for apps that want to access only the limited photo library without having iOS forcibly show the alert.

isAccessMediaLocationEnabledfalse
Only for: 
Android

Sets whether or not to request the ACCESS_MEDIA_LOCATION permission on Android.

granularPermissions["photo", "video", "audio"]
Only for: 
Android

Sets which GranularPermission values to include, determining which media permissions (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO) will be added to the Android manifest. Matches the behavior of the runtime API.

Are you using this library in an existing React Native app?

If you're not using Continuous Native Generation (CNG) or you're using native android and ios projects manually, then you need to add following permissions and configuration to your native projects:

Android

  • To access asset location (latitude and longitude EXIF tags), add ACCESS_MEDIA_LOCATION permission to your project's android/app/src/main/AndroidManifest.xml:

    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
  • Scoped storage is available from Android 10. To make expo-media-library work with scoped storage, you need to add the following configuration to your android/app/src/main/AndroidManifest.xml:

    <manifest ... > <application android:requestLegacyExternalStorage="true" ...> </manifest>

iOS

  • Add NSPhotoLibraryUsageDescription, and NSPhotoLibraryAddUsageDescription keys to your project's ios/[app]/Info.plist:

    <key>NSPhotoLibraryUsageDescription</key> <string>Give $(PRODUCT_NAME) permission to access your photos</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>Give $(PRODUCT_NAME) permission to save photos</string>

Usage

Fetching albums and displaying assets
import { useState, useEffect } from 'react'; import { Button, Text, ScrollView, StyleSheet, Image, View, Platform } from 'react-native'; import * as MediaLibrary from 'expo-media-library/legacy'; export default function App() { const [albums, setAlbums] = useState(null); const [permissionResponse, requestPermission] = MediaLibrary.usePermissions(); async function getAlbums() { if (permissionResponse.status !== 'granted') { await requestPermission(); } const fetchedAlbums = await MediaLibrary.getAlbumsAsync({ includeSmartAlbums: true, }); setAlbums(fetchedAlbums); } return ( <View style={styles.container}> <Button onPress={getAlbums} title="Get albums" /> <ScrollView> {albums && albums.map((album) => <AlbumEntry album={album} />)} </ScrollView> </View> ); } function AlbumEntry({ album }) { const [assets, setAssets] = useState([]); useEffect(() => { async function getAlbumAssets() { const albumAssets = await MediaLibrary.getAssetsAsync({ album }); setAssets(albumAssets.assets); } getAlbumAssets(); }, [album]); return ( <View key={album.id} style={styles.albumContainer}> <Text> {album.title} - {album.assetCount ?? 'no'} assets </Text> <View style={styles.albumAssetsContainer}> {assets && assets.map((asset) => ( <Image source={{ uri: asset.uri }} width={50} height={50} /> ))} </View> </View> ); } %%placeholder-start%%const styles = StyleSheet.create({ ... }); %%placeholder-end%%const styles = StyleSheet.create({ container: { flex: 1, gap: 8, justifyContent: 'center', }, albumContainer: { paddingHorizontal: 20, marginBottom: 12, gap: 4, }, albumAssetsContainer: { flexDirection: 'row', flexWrap: 'wrap', }, });

Known limitations

Empty albums

Due to system limitations on Android, it is impossible to create empty albums. It is necessary to either pass an existing asset to add to the album or a URI of a local resource, which will be used to create a new asset inside the album.

Moving assets between albums

Android 11 introduced permission changes that make the operation of moving assets between albums require confirmation from the user every time. Therefore, when creating a new asset, instead of creating the asset and then moving it to the album, it is recommended to pass the album parameter to the createAssetAsync method, which will automatically add the asset to the album without the need for user confirmation.

Wrong orientation of images

On Android, when using getAssetsAsync without resolveWithFullInfo: true, image orientation may be incorrect because EXIF data (which includes orientation) is only read when that option is enabled.

API

import * as MediaLibrary from 'expo-media-library/legacy';

No API data file found, sorry!

Permissions

Android

The following permissions are added automatically through this library's AndroidManifest.xml:

Android permissionDescription

READ_EXTERNAL_STORAGE

Allows an application to read from external storage.

WRITE_EXTERNAL_STORAGE

Allows an application to write to external storage.

READ_MEDIA_IMAGES

Allows an application to read image files from external storage.

READ_MEDIA_VIDEO

Allows an application to read video files from external storage.

READ_MEDIA_AUDIO

Allows an application to read audio files from external storage.

READ_MEDIA_VISUAL_USER_SELECTED

Allows an application to read image or video files from external storage that a user has selected via the permission prompt photo picker.

iOS

The following usage description keys are used by this library:

Info.plist keyDescription

NSPhotoLibraryUsageDescription

A message that tells the user why the app is requesting access to the user’s photo library.

NSPhotoLibraryAddUsageDescription

A message that tells the user why the app is requesting add-only access to the user’s photo library.