[Overview](https://docs.cloud.google.com/storage/docs/resumable-uploads.md.txt)

This page describes how to make a resumable upload request in the
Cloud Storage JSON and XML APIs. This protocol lets you resume an upload
operation after a communication failure interrupts the flow of data.

For information on using resumable uploads in the Google Cloud CLI and client
libraries, see [How tools and APIs use resumable uploads](https://docs.cloud.google.com/storage/docs/resumable-uploads.md.txt#behavior).

## Required roles

To get the permissions that you need to perform a resumable upload,
ask your administrator to grant you one of the following roles:

- For uploads that include an [Object Retention Lock](https://docs.cloud.google.com/storage/docs/object-lock.md.txt), ask your
  administrator to grant you the Storage Object Admin
  (`roles/storage.objectAdmin`) IAM role for the bucket.

- For all other cases, ask your administrator to grant you the Storage Object
  User (`roles/storage.objectUser`) IAM role for the bucket.

These predefined roles contain the permissions required to upload an object to a
bucket for their respective cases. To see the exact permissions that are
required, expand the **Required permissions** section:

#### Required permissions

- `storage.objects.create`
- `storage.objects.delete`
  - This permission is only required for uploads that overwrite an existing object.
- `storage.objects.setRetention`
  - This permission is only required for uploads that include an Object Retention Lock.

You can also get these permissions with other [predefined roles](https://docs.cloud.google.com/iam/docs/roles-permissions.md.txt) or
[custom roles](https://docs.cloud.google.com/iam/docs/creating-custom-roles.md.txt).

For information about granting roles on buckets, see
[Set and manage IAM policies on buckets](https://docs.cloud.google.com/storage/docs/access-control/using-iam-permissions.md.txt).

## Initiate a resumable upload session

To initiate a resumable upload session:

### JSON API

1. Have gcloud CLI [installed and initialized](https://docs.cloud.google.com/sdk/docs/install), which lets
   you generate an access token for the `Authorization` header.

2. Optionally, create a JSON file that contains the [metadata](https://docs.cloud.google.com/storage/docs/json_api/v1/objects.md.txt#resource-representations) you
   want to set on the object that you're uploading. For example, the
   following JSON file sets the `contentType` metadata of the object you
   want to upload to `image/png`:

   ```
   {
       "contentType": "image/png"
   }
   ```
3. Use [`cURL`](http://curl.haxx.se/) to call the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a
   [`POST` Object](https://docs.cloud.google.com/storage/docs/json_api/v1/objects/insert.md.txt) request:

   ```
   curl -i -X POST --data-binary @METADATA_LOCATION \
       -H "Authorization: Bearer $(gcloud auth print-access-token)" \
       -H "Content-Type: application/json" \
       -H "Content-Length: INITIAL_REQUEST_LENGTH" \
       "https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o?uploadType=resumable&name=OBJECT_NAME"
   ```

   Where:
   - `METADATA_LOCATION` is the local path to the JSON file containing the optional metadata you specified in the previous step. If you are not including a metadata file, exclude this, along with `--data-binary @` and the `Content-Type` header.
   - `INITIAL_REQUEST_LENGTH` is the number of bytes in the body of this initial request, for example `79`.
   - `BUCKET_NAME` is the name of the bucket to which you are uploading your object. For example, `my-bucket`.
   - `OBJECT_NAME` is the URL-encoded name you want to give your object. For example, `pets/dog.png`, URL-encoded as `pets%2Fdog.png`. This is not required if you included a `name` in the object metadata file in Step 2.

   If you have enabled [Cross-Origin Resource Sharing](https://docs.cloud.google.com/storage/docs/cross-origin.md.txt), you should also
   include an `Origin` header in both this and subsequent upload requests.

   Optional headers that you can add to the request include
   [`X-Upload-Content-Type`](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#xuploadcontenttype) and [`X-Upload-Content-Length`](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#xuploadcontentlength).

   If successful, the response includes a `200` status code and looks
   similar to the following:

   ```
   HTTP/2 200
   content-type: text/plain; charset=utf-8
   x-guploader-uploadid: ABgVH8_jqDHM_KOvNAJCx73r9v5fINktk9U-pXana1szCM5803tlJ7CKsRbDxkyYCrfEiNqzcZ6B7DfoDtc-bdzpH-SpVTAMEO9EQV34qG0-0yk
   location: https://storage.googleapis.com/upload/storage/v1/b/my-bucket/o?uploadType=resumable&name=cat-pic.jpeg&upload_id=ABgVH8_jqDHM_KOvNAJCx73r9v5fINktk9U-pXana1szCM5803tlJ7CKsRbDxkyYCrfEiNqzcZ6B7DfoDtc-bdzpH-SpVTAMEO9EQV34qG0-0yk
   date: Mon, 07 Jul 2025 14:57:21 GMT
   vary: Origin
   vary: X-Origin
   cache-control: no-cache, no-store, max-age=0, must-revalidate
   expires: Mon, 01 Jan 1990 00:00:00 GMT
   pragma: no-cache
   content-length: 0
   server: UploadServer
   alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
   ```
4. Save the resumable [session URI](https://docs.cloud.google.com/storage/docs/resumable-uploads.md.txt#session-uris) given in the `location` header of
   the response to your `POST` Object request.

   This URI is used in subsequent requests to upload the object data.

   > [!CAUTION]
   > **Caution:** Be careful when sharing the resumable session URI, because it can be used by anyone to upload data to the target bucket without any further authentication.

### XML API

1. Have gcloud CLI [installed and initialized](https://docs.cloud.google.com/sdk/docs/install), which lets
   you generate an access token for the `Authorization` header.

2. Use [`cURL`](http://curl.haxx.se/) to call the [XML API](https://docs.cloud.google.com/storage/docs/xml-api/overview.md.txt) with a
   [`POST` Object](https://docs.cloud.google.com/storage/docs/xml-api/post-object-resumable.md.txt) request that has an empty body:

   ```
   curl -i -X POST -H "Authorization: Bearer $(gcloud auth print-access-token)" \
       -H "Content-Length: 0" \
       -H "Content-Type: OBJECT_CONTENT_TYPE" \
       -H "x-goog-resumable: start" \
       "https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME"
   ```

   Where:
   - `OBJECT_CONTENT_TYPE` is the [content type](https://docs.cloud.google.com/storage/docs/metadata.md.txt#content-type) of the object. For example, `image/png`. If you do not specify a content type, the Cloud Storage system sets the `Content-Type` metadata for the object to be [`application/octet-stream`](https://datatracker.ietf.org/doc/html/rfc2046#section-4.5.1).
   - `BUCKET_NAME` is the name of the bucket to which you are uploading your object. For example, `my-bucket`.
   - `OBJECT_NAME` is the URL-encoded name you want to give your object. For example, `pets/dog.png`, URL-encoded as `pets%2Fdog.png`.

   If you have enabled [Cross-Origin Resource Sharing](https://docs.cloud.google.com/storage/docs/cross-origin.md.txt), you should also
   include an `Origin` header in both this and subsequent upload requests.

   If successful, the response includes a `201` status message.
3. Save the resumable [session URI](https://docs.cloud.google.com/storage/docs/resumable-uploads.md.txt#session-uris) given in the [`location` header](https://docs.cloud.google.com/storage/docs/xml-api/reference-headers.md.txt#location)
   of the response to your `POST` Object request.

   This URI is used in subsequent requests to upload the object data.

   > [!CAUTION]
   > **Caution:** Be careful when sharing the resumable session URI, because it can be used by anyone to upload data to the target bucket without any further authentication.

## Upload the data

Once you have initiated a resumable upload, there are two ways to upload the
object's data:

- **In a single chunk:** This approach is usually best, since it requires fewer requests and thus has better performance.
- **In multiple chunks:** Use this approach if you need to reduce the amount of data transferred in any single request, such as when there is a fixed time limit for individual requests, or if you don't know the total size of the upload at the time the upload begins.

### Single chunk upload

To upload the data in a single chunk:

### JSON API

1. Use [`cURL`](http://curl.haxx.se/) to call the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a `PUT`
   Object request:

   ```
   curl -i -X PUT --data-binary @OBJECT_LOCATION \
       -H "Content-Length: OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `OBJECT_LOCATION` is the local path to your object. For example, `Desktop/dog.png`.
   - `OBJECT_SIZE` is the number of bytes in your object. For example, `20000000`.
   - `SESSION_URI` is the value returned in the `location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

   Optionally, you can include headers prefixed with [`X-Goog-Meta-`](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#xgoogmeta)
   to add custom metadata for the object as part of this request.

### XML API

1. Use [`cURL`](http://curl.haxx.se/) to call the [XML API](https://docs.cloud.google.com/storage/docs/xml-api/overview.md.txt) with a `PUT`
   Object request:

   ```
   curl -i -X PUT --data-binary @OBJECT_LOCATION \
       -H "Content-Length: OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `OBJECT_LOCATION` is the local path to your object. For example, `Desktop/dog.png`.
   - `OBJECT_SIZE` is the number of bytes in your object. For example, `20000000`.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

If the upload completes in its entirety, you receive a `200 OK` or `201 Created`
response, along with any metadata associated with the resource.

If the upload request is interrupted, or if you receive a `5xx`
response, follow the procedure in [Resuming an interrupted upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#resume-upload).

### Multiple chunk upload

To upload the data in multiple chunks:

### JSON API

1. Create a chunk of data from the overall data you want to upload.

   The chunk size should be a multiple of 256 KiB (256 x 1024 bytes),
   unless it's the last chunk that completes the upload. Larger chunk sizes
   typically make uploads faster, but note that there's a tradeoff between
   speed and memory usage. It's recommended that you use at least 8 MiB for
   the chunk size.
2. Use [`cURL`](http://curl.haxx.se/) to call the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a `PUT`
   Object request:

   ```
   curl -i -X PUT --data-binary @CHUNK_LOCATION \
       -H "Content-Length: CHUNK_SIZE" \
       -H "Content-Range: bytes CHUNK_FIRST_BYTE-CHUNK_LAST_BYTE/TOTAL_OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `CHUNK_LOCATION` is the local path to the chunk that you're currently uploading.
   - `CHUNK_SIZE` is the number of bytes you're uploading in the current request. For example, `8388608`.
   - `CHUNK_FIRST_BYTE` is the starting byte in the overall object that the chunk you're uploading contains.
   - `CHUNK_LAST_BYTE` is the ending byte in the overall object that the chunk you're uploading contains.
   - `TOTAL_OBJECT_SIZE` is the total size of the object you're uploading. If you don't know the full size of your object, use `*` for this value.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

   An example `Content-Range` is `Content-Range: bytes 0-8388607/20000000`.
   See [`Content-Range`](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#contentrange) for more information about this header.

   If the request succeeds, the server responds with
   `308 Resume Incomplete`. The response contains a [`Range` header](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#range).
3. Repeat the above steps for each remaining chunk of data that you want to
   upload, using the upper value contained in the `Range` header of each
   response to determine where to start each successive chunk; you should
   not assume that the server received all bytes sent in any given request.

   Optionally, in the final request of the resumable upload you can include
   headers prefixed with [`X-Goog-Meta-`](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#xgoogmeta) to add custom metadata for
   the object.

### XML API

1. Create a chunk of data from the overall data you want to upload.

   The chunk size should be a multiple of 256 KiB (256 x 1024 bytes),
   unless it's the last chunk that completes the upload. Larger chunk sizes
   typically make uploads faster, but note that there's a tradeoff between
   speed and memory usage. It's recommended that you use at least 8 MiB for
   the chunk size.
2. Use [`cURL`](http://curl.haxx.se/) to call the [XML API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a `PUT`
   Object request:

   ```
   curl -i -X PUT --data-binary @CHUNK_LOCATION \
       -H "Content-Length: CHUNK_SIZE" \
       -H "Content-Range: bytes CHUNK_FIRST_BYTE-CHUNK_LAST_BYTE/TOTAL_OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `CHUNK_LOCATION` is the local path to the chunk that you're currently uploading.
   - `CHUNK_SIZE` is the number of bytes you're uploading in the current request. For example, `8388608`.
   - `CHUNK_FIRST_BYTE` is the starting byte in the overall object that the chunk you're uploading contains.
   - `CHUNK_LAST_BYTE` is the ending byte in the overall object that the chunk you're uploading contains.
   - `TOTAL_OBJECT_SIZE` is the total size of the object you're uploading. If you don't know the full size of your object, use `*` for this value.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

   An example `Content-Range` is `Content-Range: bytes 0-8388607/20000000`.
   See [`Content-Range`](https://docs.cloud.google.com/storage/docs/xml-api/reference-headers.md.txt#contentrange) for more information about this header.

   If the request succeeds, the server responds with
   `308 Resume Incomplete`. The response contains a [`Range` header](https://docs.cloud.google.com/storage/docs/xml-api/reference-headers.md.txt#range).
3. Repeat the above steps for each remaining chunk of data that you want to
   upload, using the upper value contained in the `Range` header of each
   response to determine where to start each successive chunk; you should
   not assume that the server received all bytes sent in any given request.

Once the upload completes in its entirety, you receive a `200 OK` or
`201 Created` response, along with any metadata associated with the resource.

If any of the chunk uploads are interrupted, or if you receive a `5xx`
response, you should either resend the interrupted chunk in its entirety or
[resume the interrupted upload from where it left off](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#resume-upload).

## Check the status of a resumable upload

If your resumable upload is interrupted, or you're not sure the upload
completed, you can check the status of the upload:

### JSON API

1. Use [`cURL`](http://curl.haxx.se/) to call the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a `PUT`
   Object request:

   ```
   curl -i -X PUT \
       -H "Content-Length: 0" \
       -H "Content-Range: bytes */OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `OBJECT_SIZE` is the total number of bytes in your object. If you don't know the full size of your object, use `*` for this value.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

### XML API

1. Use [`cURL`](http://curl.haxx.se/) to call the [XML API](https://docs.cloud.google.com/storage/docs/xml-api/overview.md.txt) with a `PUT`
   Object request:

   ```
   curl -i -X PUT \
       -H "Content-Length: 0" \
       -H "Content-Range: bytes */OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `OBJECT_SIZE` is the total number of bytes in your object. If you don't know the full size of your object, use `*` for this value.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

A `200 OK` or `201 Created` response indicates that the upload was
completed, and no further action is necessary.

A `308 Resume Incomplete` response indicates that you need to continue
uploading the data.

- If Cloud Storage has not yet persisted any bytes, the `308` response does not have a [`Range` header](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#range). In this case, you should start your upload from the beginning.
- Otherwise, the `308` response has a `Range` header, which specifies which bytes Cloud Storage has persisted so far. Use this value when [resuming an interrupted upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#resume-upload).

## Resume an interrupted upload

> [!IMPORTANT]
> **Important:** Cloud Storage [ignores](https://docs.cloud.google.com/storage/docs/resumable-uploads.md.txt#resent-data) any bytes you send at an offset that Cloud Storage [has already persisted](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#status-check).

If an upload request is terminated before receiving a response, or if you
receive a `503` or `500` response, then you need to resume
the interrupted upload from where it left off. To resume an interrupted upload:

### JSON API

1. [Check the status](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#status-check) of your resumable upload.

2. Save the upper value of the [`Range` header](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#range) contained in the response
   to your status check. If the response does not have a `Range` header,
   Cloud Storage has not yet persisted any bytes, and you should
   [upload from the beginning](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#upload-data).

3. Ensure that that object data you're about to upload begins at the byte
   following the upper value in the `Range` header.

4. If the interrupted request contained headers prefixed with
   [`X-Goog-Meta-`](https://docs.cloud.google.com/storage/docs/json_api/v1/parameters.md.txt#xgoogmeta), include those headers in the request to resume
   your upload.

5. Use [`cURL`](http://curl.haxx.se/) to call the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a `PUT`
   Object request that picks up at the byte following the value in the
   `Range` header:

   ```
   curl -i -X PUT --data-binary @PARTIAL_OBJECT_LOCATION \
       -H "Content-Length: UPLOAD_SIZE_REMAINING" \
       -H "Content-Range: bytes NEXT_BYTE-LAST_BYTE/TOTAL_OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `PARTIAL_OBJECT_LOCATION` is the local path to the remaining portion of data that you want to upload.
   - `UPLOAD_SIZE_REMAINING` is the number of bytes you're uploading in the current request. For example, uploading the rest of an object with a total size of 20000000 that was interrupted after bytes 0-42 uploaded would have an `UPLOAD_SIZE_REMAINING` of `19999957`.
   - `NEXT_BYTE` is the next integer after the value you saved in step 2. For example, if `42` is the upper value in step 2, the value for `NEXT_BYTE` is `43`.
   - `LAST_BYTE` is the ending byte contained in this `PUT` request. For example, to finish uploading an object whose total size is `20000000`, the value for `LAST_BYTE` is `19999999`.
   - `TOTAL_OBJECT_SIZE` is the total size of the object you're uploading. For example, `20000000`. If you don't know the full size of your object, use `*` for this value.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

### XML API

1. [Check the status](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#status-check) of your resumable upload.

2. Save the upper value of the [`Range` header](https://docs.cloud.google.com/storage/docs/xml-api/reference-headers.md.txt#range) contained in the
   response to your status check. If the response does not have a `Range`
   header, Cloud Storage has not yet persisted any bytes, and you
   should [upload from the beginning](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#upload-data).

3. Ensure that that object data you're about to upload begins at the byte
   following the upper value in the `Range` header.

4. Use [`cURL`](http://curl.haxx.se/) to call the [XML API](https://docs.cloud.google.com/storage/docs/xml-api/overview.md.txt) with a `PUT` Object
   request that picks up at the byte following the value in the `Range`
   header:

   ```
   curl -i -X PUT --data-binary @PARTIAL_OBJECT_LOCATION \
       -H "Content-Length: UPLOAD_SIZE_REMAINING" \
       -H "Content-Range: bytes NEXT_BYTE-LAST_BYTE/TOTAL_OBJECT_SIZE" \
       "SESSION_URI"
   ```

   Where:
   - `PARTIAL_OBJECT_LOCATION` is the local path to the remaining portion of data that you want to upload.
   - `UPLOAD_SIZE_REMAINING` is the number of bytes you're uploading in the current request. For example, uploading the rest of an object with a total size of 20000000 that was interrupted after bytes 0-42 uploaded would have an `UPLOAD_SIZE_REMAINING` of `19999957`.
   - `NEXT_BYTE` is the next integer after the value you saved in step 2. For example, if `42` is the upper value in step 2, the value for `NEXT_BYTE` is `43`.
   - `LAST_BYTE` is the ending byte contained in this `PUT` request. For example, to finish uploading an object whose total size is `20000000`, the value for `LAST_BYTE` is `19999999`.
   - `TOTAL_OBJECT_SIZE` is the total size of the object you're uploading. For example, `20000000`. If you don't know the full size of your object, use `*` for this value.
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

You can resume uploads as many times as necessary while the session URI is
active; the session URI expires after a week. When the data is successfully
uploaded, Cloud Storage responds with a `200 OK` or `201 created`
status code.

## Cancel an upload

To cancel an incomplete resumable upload and prevent any further action on it:

### JSON API

1. Use [`cURL`](http://curl.haxx.se/) to call the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) with a `DELETE`
   request:

   ```
   curl -i -X DELETE -H "Content-Length: 0" \
     "SESSION_URI"
   ```

   Where:
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

If successful, the response contains a `499` status code. Future attempts
to query or resume the upload result in a `4xx` response.

### XML API

1. Use [`cURL`](http://curl.haxx.se/) to call the [XML API](https://docs.cloud.google.com/storage/docs/xml-api/overview.md.txt) with a `DELETE`
   request:

   ```
   curl -i -X DELETE -H "Content-Length: 0" \
     "SESSION_URI"
   ```

   Where:
   - `SESSION_URI` is the value returned in the `Location` header when you [initiated the resumable upload](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads.md.txt#initiate-session).

If successful, the response contains a `204` status code, and future
attempts to query or resume the upload also result in a `204` response.

## Failure Handling

Under rare circumstances, a request to resume an interrupted upload might fail
with a non-retriable '4xx' error because permissions on the bucket have changed,
or because the integrity check on the final uploaded object detected a mismatch.
If this occurs, retry the upload by [initiating a new resumable upload
session](https://docs.cloud.google.com/storage/docs/performing-resumable-uploads#initiate-session).

## What's next

- Learn more about [resumable uploads](https://docs.cloud.google.com/storage/docs/resumable-uploads.md.txt).
- Read an overview for the [JSON API](https://docs.cloud.google.com/storage/docs/json_api.md.txt) and [XML API](https://docs.cloud.google.com/storage/docs/xml-api/overview.md.txt).
- [Stream uploads](https://docs.cloud.google.com/storage/docs/streaming-uploads.md.txt) of unknown size.
- [Batch multiple requests to the Cloud Storage JSON API](https://docs.cloud.google.com/storage/docs/batch.md.txt).