Page updated Jan 19, 2024

Migrate from v5 to v6

This guide will help you migrate Amplify JavaScript v5's Storage APIs to the new v6's Storage APIs.

Deprecated Options

Many input and output properties have been deprecated in favor of alternatives with a better developer experience. If you have identified a use case that you feel isn't covered in this migration guide, please open a GitHub issue.

The input options below have been removed in v6 from Storage APIs:

  • provider: Custom providers are no longer supported in v6. All v5 examples below use the input/output values expected for the default S3 Provider.
  • customPrefix: You can add a prefix resolver to your Storage Config to customize the key prefix per accessLevel. See Using a Custom Prefix for migration details.
  • track: Auto-tracking Storage events in pinpoint has been removed in V6. You can track Storage events using the Analytics category. See Tracking storage events for migration details.
  • ServerSideEncryption, SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, and SSEKMSKeyId: These options have been deprecated because Server-Side Encryption is automatically applied using default keys by S3 since Jan 2023.
  • cacheControl: This option has been removed and now defers to the HTTP caching behavior configured by the runtime.
  • bucket: The bucket is required for Storage configuration object as part of Amplify.configure() and has therefore been removed from input options.

Note: We have remapped all capitalized input and output keys to "camelCase" in v6.

Storage.put

The Storage.put API has been renamed to uploadData in v6. There are a few changes in the experience from v5 to v6 in addition to those mentioned above:

  • We removed the ACL option: the S3 Bucket ACL provides extra access control options that Amplify does not currently support. ACL is no longer recommended according to S3 security best practices.
  • The Expires option has been deprecated.
  • The resumable option has been removed from config as all upload tasks are resumable by default in v6. You can find the pause, resume, and cancel functions on uploadData's return value. See the v6 Storage documentation for details.
  • The progressCallback option on upload and download operations has been replaced by onProgress in v6. The function input property names loaded and total now map to transferredBytes and totalBytes.
Input

V5

// AWSS3 (Default) Provider key: string object: { ACL?: string; // removed in V6 CacheControl?: string; // removed in V6 ContentDisposition? string; ContentEncoding?: string; ContentMD5?: string; ContentType?: string; Expires?: Date; // removed in V6 Metadata?: Record<string, string>; ServerSideEncryption?: string; // removed in V6 SSECustomerAlgorithm?: string; // removed in V6 SSECustomerKey?: string; // removed in V6 SSECustomerKeyMD5?: string; // removed in V6 SSEKMSKeyId?: string; // removed in V6 Bucket: string; Key: string; Body?: string | ReadableStream<any> | Blob | Uint8Array | Buffer; Tagging?: string; // removed in V6 } // non-resumable config config?: { level?: 'public' | 'protected' | 'private'; provider?: string; // removed in V6 customPrefix?: { // removed in V6 private?: string; public?: string; protected?: string; }; track?: boolean; // removed in V6 progressCallback?: (progress: any) => any; serverSideEncryption?: string; // removed in V6 SSECustomerAlgorithm?: string; // removed in V6 SSECustomerKey?: string; // removed in V6 SSECustomerKeyMD5?: string; // removed in V6 SSEKMSKeyId?: string; // removed in V6 acl?: string; // removed in V6 bucket?: string; cacheControl?: string; // removed in V6 contentDisposition?: string; contentEncoding?: string; contentType?: string; expires?: Date; metadata?: Record<string, string>; tagging?: string; // removed in V6 useAccelerateEndpoint?: boolean; resumable?: boolean; // Not required in v6: all put operations are resumable } // resumable config config?: { // All of the standard config above plus progressCallback?: (progress: { loaded: number; total: number; }) => any; // More specific than progressCallback above completeCallback?: (event: { key?: string }) => any; errorCallback?: (err: any) => any; }
1// AWSS3 (Default) Provider
2key: string
3object: {
4 ACL?: string; // removed in V6
5 CacheControl?: string; // removed in V6
6 ContentDisposition? string;
7 ContentEncoding?: string;
8 ContentMD5?: string;
9 ContentType?: string;
10 Expires?: Date; // removed in V6
11 Metadata?: Record<string, string>;
12 ServerSideEncryption?: string; // removed in V6
13 SSECustomerAlgorithm?: string; // removed in V6
14 SSECustomerKey?: string; // removed in V6
15 SSECustomerKeyMD5?: string; // removed in V6
16 SSEKMSKeyId?: string; // removed in V6
17 Bucket: string;
18 Key: string;
19 Body?: string | ReadableStream<any> | Blob | Uint8Array | Buffer;
20 Tagging?: string; // removed in V6
21}
22// non-resumable config
23config?: {
24 level?: 'public' | 'protected' | 'private';
25 provider?: string; // removed in V6
26 customPrefix?: { // removed in V6
27 private?: string;
28 public?: string;
29 protected?: string;
30 };
31 track?: boolean; // removed in V6
32 progressCallback?: (progress: any) => any;
33 serverSideEncryption?: string; // removed in V6
34 SSECustomerAlgorithm?: string; // removed in V6
35 SSECustomerKey?: string; // removed in V6
36 SSECustomerKeyMD5?: string; // removed in V6
37 SSEKMSKeyId?: string; // removed in V6
38 acl?: string; // removed in V6
39 bucket?: string;
40 cacheControl?: string; // removed in V6
41 contentDisposition?: string;
42 contentEncoding?: string;
43 contentType?: string;
44 expires?: Date;
45 metadata?: Record<string, string>;
46 tagging?: string; // removed in V6
47 useAccelerateEndpoint?: boolean;
48 resumable?: boolean; // Not required in v6: all put operations are resumable
49}
50// resumable config
51config?: {
52 // All of the standard config above plus
53 progressCallback?: (progress: {
54 loaded: number;
55 total: number;
56 }) => any; // More specific than progressCallback above
57 completeCallback?: (event: { key?: string }) => any;
58 errorCallback?: (err: any) => any;
59}

V6

input: { key: string; data: string | Blob | ArrayBufferView | ArrayBuffer; options?: { accessLevel?: any; useAccelerateEndpoint?: boolean; onProgress?: (event: { transferredBytes: number; totalBytes?: number; }) => void; contentDisposition?: string; contentEncoding?: string; contentType?: string; metadata?: Record<string, string>; }; }
1input: {
2 key: string;
3 data: string | Blob | ArrayBufferView | ArrayBuffer;
4 options?: {
5 accessLevel?: any;
6 useAccelerateEndpoint?: boolean;
7 onProgress?: (event: {
8 transferredBytes: number;
9 totalBytes?: number;
10 }) => void;
11 contentDisposition?: string;
12 contentEncoding?: string;
13 contentType?: string;
14 metadata?: Record<string, string>;
15 };
16}
Output

V5

// Resumable StoragePutOutput { resume(): any; pause(): any; percent: number; isInProgress: boolean; } // Non-resumable StoragePutOutput { key: string; };
1// Resumable
2StoragePutOutput {
3 resume(): any;
4 pause(): any;
5 percent: number;
6 isInProgress: boolean;
7}
8
9// Non-resumable
10StoragePutOutput {
11 key: string;
12};

V6

UploadDataOutput { cancel: (message?: string) => void; pause: () => void; resume: () => void; readonly state: | 'IN_PROGRESS' | 'PAUSED' | 'CANCELED' | 'SUCCESS' | 'ERROR'; result: Promise<Item>; } Item { key: string; lastModified?: Date; size?: number; eTag?: string; metadata?: Record<string, string>; versionId?: string; contentType?: string; }
1UploadDataOutput {
2 cancel: (message?: string) => void;
3 pause: () => void;
4 resume: () => void;
5 readonly state:
6 | 'IN_PROGRESS'
7 | 'PAUSED'
8 | 'CANCELED'
9 | 'SUCCESS'
10 | 'ERROR';
11 result: Promise<Item>;
12}
13
14Item {
15 key: string;
16 lastModified?: Date;
17 size?: number;
18 eTag?: string;
19 metadata?: Record<string, string>;
20 versionId?: string;
21 contentType?: string;
22}
import { uploadData } from 'aws-amplify/storage'; const handleUpload = async (key: string, data: string | Blob) => { // Upload a file with access level `guest` as the equivalent of `public` in v5 const operation = uploadData({ key, data, options: { accessLevel: 'guest' } }); const result = await operation.result; }
1import { uploadData } from 'aws-amplify/storage';
2
3const handleUpload = async (key: string, data: string | Blob) => {
4 // Upload a file with access level `guest` as the equivalent of `public` in v5
5 const operation = uploadData({
6 key,
7 data,
8 options: {
9 accessLevel: 'guest'
10 }
11 });
12
13 const result = await operation.result;
14}
import { Storage } from 'aws-amplify'; const handleUpload = async (key: string, data: string | Blob) => { // Upload a file with access level `public` const result = await Storage.put(key, data, { level: 'public', }); }
1import { Storage } from 'aws-amplify';
2
3const handleUpload = async (key: string, data: string | Blob) => {
4 // Upload a file with access level `public`
5 const result = await Storage.put(key, data, {
6 level: 'public',
7 });
8}

Monitor Upload Progress

The progressCallback option has been replaced by onProgress in v6. The function input property names loaded and total now map to transferredBytes and totalBytes.

import { uploadData } from 'aws-amplify/storage'; const handleUpload = async (key: string, data: string | Blob) => { // Upload a file with access level `guest` as the equivalent of `public` in v5 const operation = uploadData({ key, data, options: { accessLevel: 'guest', onProgress: ({ transferredBytes, totalBytes }) => { // Progress implementation } } }); const result = await operation.result; }
1import { uploadData } from 'aws-amplify/storage';
2
3const handleUpload = async (key: string, data: string | Blob) => {
4 // Upload a file with access level `guest` as the equivalent of `public` in v5
5 const operation = uploadData({
6 key,
7 data,
8 options: {
9 accessLevel: 'guest',
10 onProgress: ({ transferredBytes, totalBytes }) => {
11 // Progress implementation
12 }
13 }
14 });
15
16 const result = await operation.result;
17}
import { Storage } from 'aws-amplify'; const handleUpload = async (key: string, data: string | Blob) => { // Upload a file with access level `public` const result = await Storage.put(key, data, { level: 'public', progressCallback: ({ loaded, total }) => { // Progress implementation } }); }
1import { Storage } from 'aws-amplify';
2
3const handleUpload = async (key: string, data: string | Blob) => {
4 // Upload a file with access level `public`
5 const result = await Storage.put(key, data, {
6 level: 'public',
7 progressCallback: ({ loaded, total }) => {
8 // Progress implementation
9 }
10 });
11}

Storage.get

The Storage.get API has been separated into two APIs in v6, getURL and downloadData. There are a few changes in the experience from v5 to v6 in addition to those mentioned above:

  • Content options (contentDisposition, contentLanguage, contentEncoding, and contentType) are no longer supported in the get API as these values are already provided in the uploaded file.
  • The following response keys inherited from AWS SDK in v5 have have been removed from the API output in v6:
    • DeleteMarker
    • AcceptRanges
    • Expiration
    • Restore
    • ChecksumXXX
    • MissingMeta
    • VersionId
    • ContentRange
    • Expires
    • WebsiteRedirectLocation
    • BucketKeyEnabled
    • StorageClass
    • RequestCharged
    • ReplicationStatus
    • PartsCount
    • TagCount
    • ObjectLockMode
    • ObjectLockRetainUntilDate
    • ObjectLockLegalHoldStatus
  • The progressCallback option on upload and download operations has been replaced by onProgress in v6. The function input property names loaded and total now map to transferredBytes and totalBytes.
Input

V5

// Assumes default S3 Provider key: string options: { level?: 'public' | 'protected' | 'private'; provider?: 'AWSS3'; customPrefix?: { // removed in V6 private?: string; public?: string; protected?: string; }; track?: boolean; // removed in V6 download?: boolean; // removed in V6 expires?: number; identityId?: string; progressCallback?: (progress: any) => any; cacheControl?: string; // removed in V6 contentDisposition?: string; // removed in V6 contentEncoding?: string; // removed in V6 contentLanguage?: string; // removed in V6 contentType?: string; // removed in V6 SSECustomerAlgorithm?: string; // removed in V6 SSECustomerKey?: string; // removed in V6 SSECustomerKeyMD5?: string; // removed in V6 validateObjectExistence?: boolean; };
1// Assumes default S3 Provider
2key: string
3options: {
4 level?: 'public' | 'protected' | 'private';
5 provider?: 'AWSS3';
6 customPrefix?: { // removed in V6
7 private?: string;
8 public?: string;
9 protected?: string;
10 };
11 track?: boolean; // removed in V6
12 download?: boolean; // removed in V6
13 expires?: number;
14 identityId?: string;
15 progressCallback?: (progress: any) => any;
16 cacheControl?: string; // removed in V6
17 contentDisposition?: string; // removed in V6
18 contentEncoding?: string; // removed in V6
19 contentLanguage?: string; // removed in V6
20 contentType?: string; // removed in V6
21 SSECustomerAlgorithm?: string; // removed in V6
22 SSECustomerKey?: string; // removed in V6
23 SSECustomerKeyMD5?: string; // removed in V6
24 validateObjectExistence?: boolean;
25};

V6

// getUrl { key: string; options?: { accessLevel?: 'guest' | 'protected' | 'private'; // targetIdentityId?: string; // included if accessLevel is 'protected' useAccelerateEndpoint?: boolean; }; } // downloadData input: { key: string; options?: { accessLevel?: 'guest' | 'protected' | 'private'; // targetIdentityId?: string; // included if accessLevel is 'protected' useAccelerateEndpoint?: boolean; onProgress?: (event: { transferredBytes: number; totalBytes?: number; }) => void; bytesRange?: { start: number; end: number; }; }; }
1// getUrl
2{
3 key: string;
4 options?: {
5 accessLevel?: 'guest' | 'protected' | 'private';
6 // targetIdentityId?: string; // included if accessLevel is 'protected'
7 useAccelerateEndpoint?: boolean;
8 };
9}
10
11// downloadData
12input: {
13 key: string;
14 options?: {
15 accessLevel?: 'guest' | 'protected' | 'private';
16 // targetIdentityId?: string; // included if accessLevel is 'protected'
17 useAccelerateEndpoint?: boolean;
18 onProgress?: (event: {
19 transferredBytes: number;
20 totalBytes?: number;
21 }) => void;
22 bytesRange?: {
23 start: number;
24 end: number;
25 };
26 };
27}
Output

V5

// download: false string // presigned url // download: true S3ProviderGetOutput { Body?: Blob; DeleteMarker?: boolean; // removed in V6 AcceptRanges?: string; // removed in V6 Expiration?: string; // removed in V6 Restore?: string; // removed in V6 LastModified?: Date; ContentLength?: number; ETag?: string; ChecksumCRC32?: string; // removed in V6 ChecksumCRC32C?: string; // removed in V6 ChecksumSHA1?: string; // removed in V6 ChecksumSHA256?: string; // removed in V6 MissingMeta?: number; // removed in V6 VersionId?: string; // removed in V6 CacheControl?: string; // removed in V6 ContentDisposition?: string; // removed in V6 ContentEncoding?: string; // removed in V6 ContentLanguage?: string; // removed in V6 ContentRange?: string; // removed in V6 ContentType?: string; Expires?: Date; // removed in V6 WebsiteRedirectLocation?: string; // removed in V6 ServerSideEncryption?: ServerSideEncryption | string; // removed in V6 Metadata?: Record<string, string>; SSECustomerAlgorithm?: string; // removed in V6 SSECustomerKeyMD5?: string; // removed in V6 SSEKMSKeyId?: string; // removed in V6 BucketKeyEnabled?: boolean; // removed in V6 StorageClass?: StorageClass | string; // removed in V6 RequestCharged?: RequestCharged | string; // removed in V6 ReplicationStatus?: ReplicationStatus | string; // removed in V6 PartsCount?: number; // removed in V6 TagCount?: number; // removed in V6 ObjectLockMode?: ObjectLockMode | string; // removed in V6 ObjectLockRetainUntilDate?: Date; // removed in V6 ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus | string; // removed in V6 $metadata: { // removed in V6 httpStatusCode?: number; requestId?: string } }
1// download: false
2string // presigned url
3
4// download: true
5S3ProviderGetOutput {
6 Body?: Blob;
7 DeleteMarker?: boolean; // removed in V6
8 AcceptRanges?: string; // removed in V6
9 Expiration?: string; // removed in V6
10 Restore?: string; // removed in V6
11 LastModified?: Date;
12 ContentLength?: number;
13 ETag?: string;
14 ChecksumCRC32?: string; // removed in V6
15 ChecksumCRC32C?: string; // removed in V6
16 ChecksumSHA1?: string; // removed in V6
17 ChecksumSHA256?: string; // removed in V6
18 MissingMeta?: number; // removed in V6
19 VersionId?: string; // removed in V6
20 CacheControl?: string; // removed in V6
21 ContentDisposition?: string; // removed in V6
22 ContentEncoding?: string; // removed in V6
23 ContentLanguage?: string; // removed in V6
24 ContentRange?: string; // removed in V6
25 ContentType?: string;
26 Expires?: Date; // removed in V6
27 WebsiteRedirectLocation?: string; // removed in V6
28 ServerSideEncryption?: ServerSideEncryption | string; // removed in V6
29 Metadata?: Record<string, string>;
30 SSECustomerAlgorithm?: string; // removed in V6
31 SSECustomerKeyMD5?: string; // removed in V6
32 SSEKMSKeyId?: string; // removed in V6
33 BucketKeyEnabled?: boolean; // removed in V6
34 StorageClass?: StorageClass | string; // removed in V6
35 RequestCharged?: RequestCharged | string; // removed in V6
36 ReplicationStatus?: ReplicationStatus | string; // removed in V6
37 PartsCount?: number; // removed in V6
38 TagCount?: number; // removed in V6
39 ObjectLockMode?: ObjectLockMode | string; // removed in V6
40 ObjectLockRetainUntilDate?: Date; // removed in V6
41 ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus | string; // removed in V6
42 $metadata: { // removed in V6
43 httpStatusCode?: number;
44 requestId?: string
45 }
46}

V6

// getUrl GetUrlOutput { url: URL; expiresAt: Date; } // downloadData DownloadDataOutput { cancel: (message?: string) => void; readonly state: TransferTaskState; result: Promise<StorageDownloadDataOutput<Item>>; } StorageDownloadDataOutput<Item> { key: string; lastModified?: Date; size?: number; eTag?: string; metadata?: Record<string, string>; versionId?: string; contentType?: string; body: { blob: () => Promise<Blob>; json: () => Promise<any>; text: () => Promise<string>; }; }
1// getUrl
2GetUrlOutput {
3 url: URL;
4 expiresAt: Date;
5}
6
7// downloadData
8DownloadDataOutput {
9 cancel: (message?: string) => void;
10 readonly state: TransferTaskState;
11 result: Promise<StorageDownloadDataOutput<Item>>;
12}
13
14StorageDownloadDataOutput<Item> {
15 key: string;
16 lastModified?: Date;
17 size?: number;
18 eTag?: string;
19 metadata?: Record<string, string>;
20 versionId?: string;
21 contentType?: string;
22 body: {
23 blob: () => Promise<Blob>;
24 json: () => Promise<any>;
25 text: () => Promise<string>;
26 };
27}

Get URL Only (Default)

import { getUrl } from 'aws-amplify/storage'; const handleGetUrl = async (key: string) => { const url = await getUrl({ key, options: { validateObjectExistence: true }, }); }
1import { getUrl } from 'aws-amplify/storage';
2
3const handleGetUrl = async (key: string) => {
4 const url = await getUrl({
5 key,
6 options: {
7 validateObjectExistence: true
8 },
9 });
10}
import { Storage } from 'aws-amplify'; const handleGetUrl = async (key: string) => { const url = await Storage.get(key, { validateObjectExistence: true }); }
1import { Storage } from 'aws-amplify';
2
3const handleGetUrl = async (key: string) => {
4 const url = await Storage.get(key, {
5 validateObjectExistence: true
6 });
7}

Download File Content to Memory

import { downloadData } from 'aws-amplify/storage'; const handleDownload = async (key: string) => { const { body, eTag } = await downloadData({ key }).result; }
1import { downloadData } from 'aws-amplify/storage';
2
3const handleDownload = async (key: string) => {
4 const { body, eTag } = await downloadData({ key }).result;
5}
import { Storage } from 'aws-amplify'; const handleDownload = async (key: string) => { const { Body, ETag } = await Storage.get(key, { download: true }); }
1import { Storage } from 'aws-amplify';
2
3const handleDownload = async (key: string) => {
4 const { Body, ETag } = await Storage.get(key, {
5 download: true
6 });
7}

Monitor Download Progress

The progressCallback option has been replaced by onProgress in v6. The function input property names loaded and total now map to transferredBytes and totalBytes.

import { downloadData } from 'aws-amplify/storage'; const handleDownload = async (key: string) => { const { body, eTag } = await downloadData({ key, options: { onProgress: ({ transferredBytes, totalBytes }) => { // Progress implementation } } }).result; }
1import { downloadData } from 'aws-amplify/storage';
2
3const handleDownload = async (key: string) => {
4 const { body, eTag } = await downloadData({
5 key,
6 options: {
7 onProgress: ({ transferredBytes, totalBytes }) => {
8 // Progress implementation
9 }
10 }
11 }).result;
12}
import { Storage } from 'aws-amplify'; const handleDownload = async (key: string) => { const { Body, ETag } = await Storage.get(key, { download: true, progressCallback: ({ loaded, total }) => { // Progress implementation } }); }
1import { Storage } from 'aws-amplify';
2
3const handleDownload = async (key: string) => {
4 const { Body, ETag } = await Storage.get(key, {
5 download: true,
6 progressCallback: ({ loaded, total }) => {
7 // Progress implementation
8 }
9 });
10}

Storage.copy

In addition to the changes mentioned above, the copy API in v6 no longer supports content options (contentDisposition, contentLanguage, and contentType) as these values are already provided by the existing file.

Input

V5

// Assumes default S3 Provider src: { key: string; level?: string; identityId?: string; } dest: { level?: string; key: string; } config?: { provider?: 'AWSS3'; customPrefix?: { // removed in V6 public?: string; protected?: string; private?: string; }; track?: boolean; // removed in V6 bucket?: string; cacheControl?: string; // removed in V6 contentDisposition?: string; // removed in V6 contentLanguage?: string; // removed in V6 contentType?: string; // removed in V6 expires?: Date; tagging?: string; // removed in V6 acl?: | 'private' | 'authenticated-read' | 'aws-exec-read' | 'bucket-owner-full-control' | 'bucket-owner-read' | 'public-read' | 'public-read-write' | string; metadata?: Record<string, string>; serverSideEncryption?: 'AES256' | 'aws:kms'; SSECustomerAlgorithm?: string; // removed in V6 SSECustomerKey?: string; // removed in V6 SSECustomerKeyMD5?: string; // removed in V6 SSEKMSKeyId?: string; // removed in V6 }
1// Assumes default S3 Provider
2src: {
3 key: string;
4 level?: string;
5 identityId?: string;
6}
7dest: {
8 level?: string;
9 key: string;
10}
11config?: {
12 provider?: 'AWSS3';
13 customPrefix?: { // removed in V6
14 public?: string;
15 protected?: string;
16 private?: string;
17 };
18 track?: boolean; // removed in V6
19 bucket?: string;
20 cacheControl?: string; // removed in V6
21 contentDisposition?: string; // removed in V6
22 contentLanguage?: string; // removed in V6
23 contentType?: string; // removed in V6
24 expires?: Date;
25 tagging?: string; // removed in V6
26 acl?:
27 | 'private'
28 | 'authenticated-read'
29 | 'aws-exec-read'
30 | 'bucket-owner-full-control'
31 | 'bucket-owner-read'
32 | 'public-read'
33 | 'public-read-write'
34 | string;
35 metadata?: Record<string, string>;
36 serverSideEncryption?: 'AES256' | 'aws:kms';
37 SSECustomerAlgorithm?: string; // removed in V6
38 SSECustomerKey?: string; // removed in V6
39 SSECustomerKeyMD5?: string; // removed in V6
40 SSEKMSKeyId?: string; // removed in V6
41}

V6

input: { source: { key: string; accessLevel?: 'guest' | 'protected' | 'private'; // Included when accessLevel 'protected' targetIdentityId?: string; }; destination: { key: string; accessLevel?: any; }; }
1input: {
2 source: {
3 key: string;
4 accessLevel?: 'guest' | 'protected' | 'private';
5 // Included when accessLevel 'protected'
6 targetIdentityId?: string;
7 };
8 destination: {
9 key: string;
10 accessLevel?: any;
11 };
12}
Output

V5

S3ProviderCopyOutput { key: string; }
1S3ProviderCopyOutput {
2 key: string;
3}

V6

CopyOutput { key: string; }
1CopyOutput {
2 key: string;
3}
import { copy } from 'aws-amplify/storage'; const handleCopy = async (sourceKey: string, destinationKey: string) => { const { key } = await copy({ source: { key: sourceKey }, destination: { key: destinationKey }, }); };
1import { copy } from 'aws-amplify/storage';
2
3const handleCopy = async (sourceKey: string, destinationKey: string) => {
4 const { key } = await copy({
5 source: {
6 key: sourceKey
7 },
8 destination: {
9 key: destinationKey
10 },
11 });
12};
import { Storage } from 'aws-amplify'; const handleCopy = async (sourceKey: string, destinationKey: string) => { const { key } = await Storage.copy( src: { key: sourceKey }, dest: { key: destinationKey } ) };
1import { Storage } from 'aws-amplify';
2
3const handleCopy = async (sourceKey: string, destinationKey: string) => {
4 const { key } = await Storage.copy(
5 src: {
6 key: sourceKey
7 },
8 dest: {
9 key: destinationKey
10 }
11 )
12};

Storage.remove

In addition to the changes mentioned above, the output of the remove API in v6 now only returns the key of the removed file. DeleteMarker, VersionId, RequestCharged, and $metadata have been removed from the output.

Input

V5

// Assumes default S3 Provider key: string config?: { level?: 'public' | 'protected' | 'private'; provider?: 'AWSS3'; customPrefix?: { // removed in V6 public?: string; protected?: string; private?: string; }; track?: boolean; // removed in V6 bucket?: string; }
1// Assumes default S3 Provider
2key: string
3 config?: {
4 level?: 'public' | 'protected' | 'private';
5 provider?: 'AWSS3';
6 customPrefix?: { // removed in V6
7 public?: string;
8 protected?: string;
9 private?: string;
10 };
11 track?: boolean; // removed in V6
12 bucket?: string;
13}

V6

input: { key: string; options?: { accessLevel?: any; useAccelerateEndpoint?: boolean; }; }
1input: {
2 key: string;
3 options?: {
4 accessLevel?: any;
5 useAccelerateEndpoint?: boolean;
6 };
7}
Output

V5

DeleteMarker?: boolean; // removed in V6 VersionId?: string; // removed in V6 RequestCharged?: 'requester' | string; // removed in V6 $metadata: { // removed in V6 httpStatusCode?: number; requestId?: string; extendedRequestId?: string; cfId?: string; attempts?: number; totalRetryDelay?: number; };
1DeleteMarker?: boolean; // removed in V6
2VersionId?: string; // removed in V6
3RequestCharged?: 'requester' | string; // removed in V6
4$metadata: { // removed in V6
5 httpStatusCode?: number;
6 requestId?: string;
7 extendedRequestId?: string;
8 cfId?: string;
9 attempts?: number;
10 totalRetryDelay?: number;
11};

V6

RemoveOutput { key: string; }
1RemoveOutput {
2 key: string;
3}
import { remove } from 'aws-amplify/storage'; const handleRemove = async (key: string, accessLevel: string) => { await remove({ key, options: { // accessLevel is required if other than 'guest' accessLevel } }); }
1import { remove } from 'aws-amplify/storage';
2
3const handleRemove = async (key: string, accessLevel: string) => {
4 await remove({
5 key,
6 options: {
7 // accessLevel is required if other than 'guest'
8 accessLevel
9 }
10 });
11}
import { Storage } from 'aws-amplify'; const handleRemove = async (key: string, accessLevel: string) => { await Storage.remove(key, { // accessLevel is required if other than 'public' level: accessLevel }); }
1import { Storage } from 'aws-amplify';
2
3const handleRemove = async (key: string, accessLevel: string) => {
4 await Storage.remove(key, {
5 // accessLevel is required if other than 'public'
6 level: accessLevel
7 });
8}

Storage.list

There are a few changes in the list API from v5 to v6 in addition to those mentioned above:

  • The path parameter is now the optional prefix parameter. If you want to list all files in the public folder, you do not need to provide an empty string as the prefix.
  • The hasNextToken output property has been removed. You can check that nextToken is defined to check if there are more items to retrieve.
Input

V5

// Assumes default S3 Provider path: string, config?: { level?: 'public' | 'protected' | 'private'; provider?: 'AWSS3'; customPrefix?: { // removed in V6 private?: string; public?: string; protected?: string; }; track?: boolean; // removed in V6 bucket?: string; pageSize?: number | 'ALL'; identityId?: string; nextToken?: string; }
1// Assumes default S3 Provider
2path: string,
3config?: {
4 level?: 'public' | 'protected' | 'private';
5 provider?: 'AWSS3';
6 customPrefix?: { // removed in V6
7 private?: string;
8 public?: string;
9 protected?: string;
10 };
11 track?: boolean; // removed in V6
12 bucket?: string;
13 pageSize?: number | 'ALL';
14 identityId?: string;
15 nextToken?: string;
16}

V6

// Paginated List input { prefix?: string; options?: { listAll?: false; accessLevel?: 'guest' | 'protected' | 'private'; pageSize?: number; nextToken?: string; useAccelerateEndpoint?: boolean; // Included if accessLevel is 'protected' targetIdentityId?: string'; }; } // List All input { prefix?: string; options?: { listAll: true; accessLevel?: 'guest' | 'protected' | 'private'; useAccelerateEndpoint?: boolean; // Included if accessLevel is 'protected' targetIdentityId?: string'; }; }
1// Paginated List
2input {
3 prefix?: string;
4 options?: {
5 listAll?: false;
6 accessLevel?: 'guest' | 'protected' | 'private';
7 pageSize?: number;
8 nextToken?: string;
9 useAccelerateEndpoint?: boolean;
10 // Included if accessLevel is 'protected'
11 targetIdentityId?: string';
12 };
13}
14
15// List All
16input {
17 prefix?: string;
18 options?: {
19 listAll: true;
20 accessLevel?: 'guest' | 'protected' | 'private';
21 useAccelerateEndpoint?: boolean;
22 // Included if accessLevel is 'protected'
23 targetIdentityId?: string';
24 };
25}
Output

V5

StorageListOutput { results: S3ProviderListOutputItem[]; nextToken?: string; hasNextToken: boolean; // removed in V6 }; S3ProviderListOutputItem { key: string; eTag: string; lastModified: Date; size: number; }
1StorageListOutput {
2 results: S3ProviderListOutputItem[];
3 nextToken?: string;
4 hasNextToken: boolean; // removed in V6
5};
6
7S3ProviderListOutputItem {
8 key: string;
9 eTag: string;
10 lastModified: Date;
11 size: number;
12}

V6

// Paginated List ListPaginateOutput { items: ListOutputItem[]; nextToken?: string; } // List All ListAllOutput { items: ListOutputItem[]; } ListOutputItem { key: string; lastModified?: Date; size?: number; eTag?: string; }
1// Paginated List
2ListPaginateOutput {
3 items: ListOutputItem[];
4 nextToken?: string;
5}
6
7// List All
8ListAllOutput {
9 items: ListOutputItem[];
10}
11
12ListOutputItem {
13 key: string;
14 lastModified?: Date;
15 size?: number;
16 eTag?: string;
17}

Paginated List (Default)

import { list } from 'aws-amplify/storage'; const PAGE_SIZE = 20; let nextToken = undefined; let hasNextPage = true; const loadNextPage = async () => { if (hasNextPage) { let response = await list({ options: { pageSize: PAGE_SIZE, nextToken: nextToken } }); if (response.nextToken) { nextToken = response.nextToken; } else { nextToken = undefined; hasNextPage = false; } // render list items from response.results } };
1import { list } from 'aws-amplify/storage';
2
3const PAGE_SIZE = 20;
4let nextToken = undefined;
5let hasNextPage = true;
6
7const loadNextPage = async () => {
8 if (hasNextPage) {
9 let response = await list({
10 options: {
11 pageSize: PAGE_SIZE,
12 nextToken: nextToken
13 }
14 });
15 if (response.nextToken) {
16 nextToken = response.nextToken;
17 } else {
18 nextToken = undefined;
19 hasNextPage = false;
20 }
21 // render list items from response.results
22 }
23};
import { Storage } from 'aws-amplify'; const PAGE_SIZE = 20; let nextToken = undefined; let hasNextPage = true; const loadNextPage = async () => { if (hasNextPage) { let response = await Storage.list('', { pageSize: PAGE_SIZE, nextToken: nextToken }); if (response.hasNextToken) { nextToken = response.nextToken; } else { nextToken = undefined; hasNextPage = false; } // render list items from response.results } };
1import { Storage } from 'aws-amplify';
2
3const PAGE_SIZE = 20;
4let nextToken = undefined;
5let hasNextPage = true;
6
7const loadNextPage = async () => {
8 if (hasNextPage) {
9 let response = await Storage.list('', {
10 pageSize: PAGE_SIZE,
11 nextToken: nextToken
12 });
13 if (response.hasNextToken) {
14 nextToken = response.nextToken;
15 } else {
16 nextToken = undefined;
17 hasNextPage = false;
18 }
19 // render list items from response.results
20 }
21};

All Files

import { list } from 'aws-amplify/storage'; const handleListAll = async ( prefix: string, accessLevel: string, id: string ) => { const { items } = list({ prefix, options: { listAll: true, // accessLevel and targetIdentityId not required if accessLevel is 'guest' accessLevel, targetIdentityId: id, } }); }
1import { list } from 'aws-amplify/storage';
2
3const handleListAll = async (
4 prefix: string,
5 accessLevel: string,
6 id: string
7) => {
8 const { items } = list({
9 prefix,
10 options: {
11 listAll: true,
12 // accessLevel and targetIdentityId not required if accessLevel is 'guest'
13 accessLevel,
14 targetIdentityId: id,
15 }
16 });
17}
import { Storage } from 'aws-amplify'; const handleListAll = async ( prefix: string, accessLevel: string, id: string ) => { const { results } = Storage.list(prefix, { pageSize: 'ALL', // level and identityId not required if level is 'public' level: accessLevel, identityId: id }); }
1import { Storage } from 'aws-amplify';
2
3const handleListAll = async (
4 prefix: string,
5 accessLevel: string,
6 id: string
7) => {
8 const { results } = Storage.list(prefix, {
9 pageSize: 'ALL',
10 // level and identityId not required if level is 'public'
11 level: accessLevel,
12 identityId: id
13 });
14}

Storage.getProperties

In addition to the changes mentioned above, the getProperties API in v6 also adds key to the result.

Input

V5

key: string config?: { level?: 'public' | 'protected' | 'private'; provider?: string; // removed in V6 customPrefix?: { // removed in V6 private?: string; public?: string; protected?: string; }; track?: boolean; // removed in V6 SSECustomerAlgorithm?: string; // removed in V6 SSECustomerKey?: string; // removed in V6 SSECustomerKeyMD5?: string; // removed in V6 }
1key: string
2 config?: {
3 level?: 'public' | 'protected' | 'private';
4 provider?: string; // removed in V6
5 customPrefix?: { // removed in V6
6 private?: string;
7 public?: string;
8 protected?: string;
9 };
10 track?: boolean; // removed in V6
11 SSECustomerAlgorithm?: string; // removed in V6
12 SSECustomerKey?: string; // removed in V6
13 SSECustomerKeyMD5?: string; // removed in V6
14}

V6

input: { key: string; options?: { accessLevel?: 'guest' | 'protected' | 'private'; useAccelerateEndpoint?: boolean; // Included if accessLevel is 'protected' targetIdentityId?: string; }; }
1input: {
2 key: string;
3 options?: {
4 accessLevel?: 'guest' | 'protected' | 'private';
5 useAccelerateEndpoint?: boolean;
6 // Included if accessLevel is 'protected'
7 targetIdentityId?: string;
8 };
9}
Output

V5

StorageGetPropertiesOutput { contentType: string; contentLength: number; eTag: string; lastModified: Date; metadata: Record<string, string>; };
1StorageGetPropertiesOutput {
2 contentType: string;
3 contentLength: number;
4 eTag: string;
5 lastModified: Date;
6 metadata: Record<string, string>;
7};

V6

GetPropertiesOutput { key: string; lastModified?: Date; size?: number'; eTag?: string'; metadata?: Record<string, string>'; versionId?: string; contentType?: string; }
1GetPropertiesOutput {
2 key: string;
3 lastModified?: Date;
4 size?: number';
5 eTag?: string';
6 metadata?: Record<string, string>';
7 versionId?: string;
8 contentType?: string;
9}
import { getProperties } from 'aws-amplify/storage'; const handleGetProperties = async ( key: string, accessLevel: string ) => { const result = await getProperties({ key: 'key', options: { // accessLevel not required if accessLevel is 'guest' accessLevel, } }); }
1import { getProperties } from 'aws-amplify/storage';
2
3const handleGetProperties = async (
4 key: string,
5 accessLevel: string
6) => {
7 const result = await getProperties({
8 key: 'key',
9 options: {
10 // accessLevel not required if accessLevel is 'guest'
11 accessLevel,
12 }
13 });
14}
import { Storage } from 'aws-amplify'; const handleGetProperties = async ( key: string, accessLevel: string ) => { const result = await Storage.getProperties(key, { // level not required if level is 'public' level: accessLevel, }); }
1import { Storage } from 'aws-amplify';
2
3const handleGetProperties = async (
4 key: string,
5 accessLevel: string
6) => {
7 const result = await Storage.getProperties(key, {
8 // level not required if level is 'public'
9 level: accessLevel,
10 });
11}

Storage.cancel

The process for cancelling a request has changed in v6. In v5, you have to maintain the promise or UploadTask reference returned from a Storage API call, and supply it as input to the Storage.cancel API. In v6, cancel is a function returned with the result of a Storage operation. To cancel an operation, you will call operation.cancel().

import { downloadData } from 'aws-amplify/storage'; const operation = downloadData({ apiName, path, options }); operation.response.then(result => { // GET operation completed successfully }).catch(error => { // If the error is because the request was cancelled you can confirm here. if(isCancelError(error)) { // 'my message for cancellation' console.log(error.message); } }) // To cancel the above request operation.cancel('my message for cancellation');
1import { downloadData } from 'aws-amplify/storage';
2
3const operation = downloadData({
4 apiName,
5 path,
6 options
7});
8
9operation.response.then(result => {
10 // GET operation completed successfully
11}).catch(error => {
12 // If the error is because the request was cancelled you can confirm here.
13 if(isCancelError(error)) {
14 // 'my message for cancellation'
15 console.log(error.message);
16 }
17})
18
19// To cancel the above request
20operation.cancel('my message for cancellation');
import { Storage } from 'aws-amplify'; const operation = Storage.get(key, options); operation.then(result => { // GET operation completed successfully }).catch(error => { // If the error is because the request was cancelled you can confirm here. if(Storage.isCancel(error)) { // 'my message for cancellation' console.log(error.message); } }); // To cancel the above request Storage.cancel(operation, 'my message for cancellation');
1import { Storage } from 'aws-amplify';
2
3const operation = Storage.get(key, options);
4
5operation.then(result => {
6 // GET operation completed successfully
7}).catch(error => {
8 // If the error is because the request was cancelled you can confirm here.
9 if(Storage.isCancel(error)) {
10 // 'my message for cancellation'
11 console.log(error.message);
12 }
13});
14
15// To cancel the above request
16Storage.cancel(operation, 'my message for cancellation');

Using a Custom Prefix

If you would like to upload or download items with a customPrefix, you can configure a prefix resolver in the second parameter of Amplify.configure, libraryOptions. Keep in mind that you will need to resolve each accessLevel in the custom prefixResolver. The example below shows the default for protected and private access levels and a customPrefix for guest.

import { uploadData } from 'aws-amplify/storage'; import { Amplify } from 'aws-amplify'; import amplifyconfig from './amplifyconfiguration.json'; const libraryOptions = { Storage: { S3: { prefixResolver: async ({ accessLevel, targetIdentityId }) => { if (accessLevel === 'guest') { return 'publicPrefix/'; } else if (accessLevel === 'protected') { return `protected/${targetIdentityId}/`; } else { return `private/${targetIdentityId}/`; } } } } }; Amplify.configure(amplifyConfig, libraryOptions); const handleUpload = async (key: string, data: string | Blob) => { // Upload a file with access level `guest` as the equivalent of `public` in v5 const operation = uploadData({ key, data, options: { accessLevel: 'guest' } }); const result = await operation.result; }
1import { uploadData } from 'aws-amplify/storage';
2import { Amplify } from 'aws-amplify';
3import amplifyconfig from './amplifyconfiguration.json';
4
5const libraryOptions = {
6 Storage: {
7 S3: {
8 prefixResolver: async ({ accessLevel, targetIdentityId }) => {
9 if (accessLevel === 'guest') {
10 return 'publicPrefix/';
11 } else if (accessLevel === 'protected') {
12 return `protected/${targetIdentityId}/`;
13 } else {
14 return `private/${targetIdentityId}/`;
15 }
16 }
17 }
18 }
19};
20
21Amplify.configure(amplifyConfig, libraryOptions);
22
23const handleUpload = async (key: string, data: string | Blob) => {
24 // Upload a file with access level `guest` as the equivalent of `public` in v5
25 const operation = uploadData({
26 key,
27 data,
28 options: {
29 accessLevel: 'guest'
30 }
31 });
32
33 const result = await operation.result;
34}
import { Storage } from 'aws-amplify'; const handleUpload = async (key: string, data: string | Blob) => { // Upload a file with access level `public` const result = await Storage.put(key, data, { level: 'public', customPrefix: { public: 'publicPrefix' } }); }
1import { Storage } from 'aws-amplify';
2
3const handleUpload = async (key: string, data: string | Blob) => {
4 // Upload a file with access level `public`
5 const result = await Storage.put(key, data, {
6 level: 'public',
7 customPrefix: {
8 public: 'publicPrefix'
9 }
10 });
11}

Tracking storage events

The track option has been removed from Storage and its APIs in v6. Previously, in v5, enabling this option would automatically send analytics events to Pinpoint following the success or failure of Storage API calls. The analytic events sent were defined by Amplify and therefore not configurable. In v6, this option has been removed but you can continue to track Storage API results in a more predictable and configurable way using the Analytics category.

The table below lists the analytics events previously associated to v5 APIs and the corresponding v6 APIs they should now be associated with instead.

Analytics eventV5 APIV6 API
'copy'copycopy
'download'get (download: true)downloadData
'getSignedUrl'getgetUrl
'getProperties'getPropertiesgetProperties
'upload'putuploadData
'delete'removeremove
'list'listlist

The example below records an analytics event similar to what you would have seen in v5, but does not prescribe a format or content that needs to be followed. Instead, it is fully configurable and should be structured to best suit your analytics needs. Learn more about using the Analytics category.

import { list } from 'aws-amplify/storage'; import { record } from 'aws-amplify/analytics'; const prefix = 'photos/'; try { const result = await list({ prefix }); record({ name: 'list', attributes: { result: 'success' }, }); // Do something with the result } catch (error) { record({ name: 'list', attributes: { result: 'failure' }, }); // Do something with the error };
1import { list } from 'aws-amplify/storage';
2import { record } from 'aws-amplify/analytics';
3
4const prefix = 'photos/';
5
6try {
7 const result = await list({ prefix });
8 record({
9 name: 'list',
10 attributes: { result: 'success' },
11 });
12 // Do something with the result
13} catch (error) {
14 record({
15 name: 'list',
16 attributes: { result: 'failure' },
17 });
18 // Do something with the error
19};
import { Storage } from 'aws-amplify'; const prefix = 'photos/'; Storage.configure({ track: true }); try { const result = Storage.list(prefix); // Do something with the result } catch (error) { // Do something with the error }
1import { Storage } from 'aws-amplify';
2
3const prefix = 'photos/';
4
5Storage.configure({ track: true });
6
7try {
8 const result = Storage.list(prefix);
9 // Do something with the result
10} catch (error) {
11 // Do something with the error
12}