Dartvel, home
Docs
Features
Studio
Cloud
Compared

Search the site

GitHub
pub.dev

GETTING STARTED

Getting started
Existing Flutter apps
Existing Native apps
Run on your phone

APP

UI and styling
Routing
State
Accessibility
Keyboard shortcuts
Localization
Devices and desktop
Native device access
Media, 3D and XR

DATA

Data models
Forms
Search
Sync and offline
Import and export
Change capture
Database
Cache
File storage
Images
Privacy and erasure

BACKEND

Backend functions
Auth and sessions
Authorization
Queues and jobs
Workers and memory
Notifications and mail
Outbound HTTP
AI
Webhooks
GraphQL and OpenAPI
API keys and OAuth
Multi-tenancy
Billing and commerce
Modules

OPERATIONS

Edge security
Secrets and environments
Monitoring
Releases

SHIPPING

Build targets
Telegram Mini Apps
Static web hosting
Servers and deploying

REFERENCE

Testing
CLI reference
Coding agents

DATA

File storage

Store files with one API on the device's own disk, a server's disk, S3, Google Cloud Storage or Azure Blob Storage.

Swap the adapter and your code stays the same.

ON THIS PAGE

Configure a storage adapter

Put, get, list and delete files

Files on the device: DV.Platform.fileStorage

Status

Configure a storage adapter

The same calls wherever the files are. On a server that can be the server's own disk; on a device it is the directory the application owns, which is what a file manager writes into. A bucket is one more adapter behind them.

// The filesystem this process is standing on. On a server that is the
// server's disk; on a device it is the directory the application owns, which
// is what a file manager writes into. Same calls either way.
void storeOnDisk(String directory) {
  DV.FileStorage.configure(DVLocalFileStorageAdapter(root: directory));
}

Copy code to clipboard

// A bucket is one more adapter behind the same calls. Swapping this line is
// the whole of moving from a disk to S3.
void configureStorage() {
  DV.FileStorage.configure(S3FileStorageAdapter(
    bucket: 'uploads',
    region: 'eu-west-1',
    credentials: DVAwsCredentials(
      accessKeyId: DV.Secrets.get('AWS_ACCESS_KEY_ID'),
      secretAccessKey: DV.Secrets.get('AWS_SECRET_ACCESS_KEY'),
    ),
  ));
}

Copy code to clipboard

DVLocalFileStorageAdapter

Stores files in: The filesystem: a server's disk, or the directory an app owns on a device

DVMemoryFileStorageAdapter

Stores files in: Memory, the default

S3FileStorageAdapter

Stores files in: Amazon S3, or any S3 API with endpoint:

GcsFileStorageAdapter

Stores files in: Google Cloud Storage

AzureBlobFileStorageAdapter

Stores files in: Azure Blob Storage

A key is a path inside the root, and often comes from a request. One that climbs out of the root is refused, so a ../ in a key cannot read or overwrite anything else the process can reach.

A browser has no such filesystem, so DVLocalFileStorageAdapter there answers every call with a 501. On a device in a browser, use DV.Platform.fileStorage below, which is the origin private file system.

Put, get, list and delete files

await DV.FileStorage.put('avatars/ada.png', bytes, contentType: 'image/png');

if (await DV.FileStorage.exists('avatars/ada.png')) {
  final List<int> image = await DV.FileStorage.get('avatars/ada.png');
  DV.log('${image.length} bytes');
}

final List<String> avatars = await DV.FileStorage.list(prefix: 'avatars/');
await DV.FileStorage.delete('avatars/ada.png');

Copy code to clipboard

Keys are paths you choose, such as avatars/ada.png.

There is no public URL or signed URL method. Serve files through a backend function.

Use DV.FileStorage

DV.Storage is the old name. It still works and is deprecated, so new code should not use it.

Files on the device: DV.Platform.fileStorage

DV.Platform.fileStorage is DV.FileStorage on the device's own disk: the same calls, bound to the local adapter whatever DV.FileStorage is configured with. Keys go in the directory each platform gives an app for its own files, which needs no permission anywhere.

// The device's own disk, whatever adapter DV.FileStorage is configured with.
// App-private: no permission on any platform.
await DV.Platform.fileStorage.put('drafts/note.txt', bytes);
final List<String> drafts = await DV.Platform.fileStorage.list(prefix: 'drafts/');
await DV.Platform.fileStorage.cache.put('thumbs/note.png', bytes);

// A file the person picks. Choosing it is the grant, so nothing is declared.
final List<DVPickedFile> picked = await DV.Platform.fileStorage.pick(type: 'image');
for (final DVPickedFile file in picked) {
  await DV.Platform.fileStorage.put('attachments/${file.name}', await file.readBytes());
}

// A folder the person picks, as a storage with the same calls.
final DVStorage? folder = await DV.Platform.fileStorage.pickDirectory();
await folder?.put('export.csv', bytes);

// Wider access, declared under dartvel.fileStorage in pubspec.yaml.
try {
  await DV.Platform.fileStorage.requestAccess(.photos);
} on DVFileAccessDenied catch (refused) {
  DV.log(refused.reason);
}

Copy code to clipboard

Android

App files: dartvel-files in the app's files directory; cache in its cache directory

Files the person picks: The system picker, a private copy by path. No folders yet.

iOS

App files: Documents in the app container (in the Files app with shareAppFiles)

Files the person picks: Not bound yet

macOS

App files: ~/Library/Application Support/<app>

Files the person picks: Open panel and folder panel

Windows

App files: %LOCALAPPDATA%\<app>\Files

Files the person picks: Open dialog and folder dialog

Linux and embedded Linux

App files: $XDG_DATA_HOME/<app> (~/.local/share/<app>)

Files the person picks: GTK file and folder chooser

Web

App files: The origin private file system

Files the person picks: A file input in every browser. Folders: showDirectoryPicker in Chromium (read and write); a folder input elsewhere (read only)

Access beyond the app's own files

Declare it once under dartvel.fileStorage in pubspec.yaml, or in your DartvelConfig class. The build writes it the way each platform expects, and requestAccess asks for it at run time.

# What DV.Platform.fileStorage may reach beyond the app's own directory.
# Leave it out and the app reads and writes only its own files.
fileStorage:
  access: [photos, documents]   # also: media, allFiles
  reason: Attach photos and receipts to your orders.
  shareAppFiles: true           # iOS: show the app's Documents in Files

Copy code to clipboard

photos

Android (written to the manifest): READ_MEDIA_IMAGES (13+), READ_MEDIA_VISUAL_USER_SELECTED (14+), READ_EXTERNAL_STORAGE (12 and below)

iOS and macOS: NSPhotoLibraryUsageDescription with your reason; macOS: pictures read-only entitlement

media

Android (written to the manifest): Photos plus READ_MEDIA_VIDEO and READ_MEDIA_AUDIO

iOS and macOS: As photos; macOS also movies and music entitlements

documents

Android (written to the manifest): Nothing: the picker is the grant

iOS and macOS: macOS: user-selected read-write entitlement

allFiles

Android (written to the manifest): MANAGE_EXTERNAL_STORAGE (11+): a Settings switch, and Google Play allows it only for apps that need it

iOS and macOS: iOS has none; macOS sandbox has none (the build says so)

shareAppFiles: true adds UIFileSharingEnabled and LSSupportsOpeningDocumentsInPlace on iOS.

Windows, Linux and the web need nothing at build time: a desktop process reads what its user can, and a browser asks when the person picks.

Keys you already set in Info.plist or the entitlements are yours: the build keeps them and does not write a second copy.

requestAccess throws DVFileAccessDenied when the person refuses, and a StateError naming the pubspec key when the access was never declared.

DV.Platform.files is deprecated

Use DV.Platform.fileStorage: put, get and delete in the same directory on Android and the web, and every other target too.

Status

Partial

Spec section: File Storage

Planned work and implementation limits

No putStream or getStream, so a file is read and written whole.

PREVIOUS Cache Remember values and drop them by tag
NEXT Images Resized image variants for web builds
GitHub
pub.dev
npm
Acknowledgements
Privacy
Terms

FSL-1.1-MIT licensed. Built with Dartvel.

Dartvel is made by

SigmaDev Digital

To the bottom