> For the complete documentation index, see [llms.txt](https://docs.fastn.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fastn.ai/tutorials-1/data-migrations/setting-up-a-google-drive-to-gcs-migration-flow.md).

# Setting Up a Google Drive to GCS Migration Flow

## **1. Start the Flow**

You can start the flow by selecting **New API Request** as the trigger.

![Flow trigger step configured with New API Request as the starting point](/files/IfImyUCaecETZYiL3Xvm)<br>

### Initiate Your Flow Variables

When the flow starts, the following important variables are initialized:

<figure><img src="/files/T0f3cfI9pcITHfBxo55B" alt="Flow variables initialization step with MIME handling for Docs, Sheets, Slides, and Drawings"><figcaption></figcaption></figure>

{% hint style="info" %}
You also define MIME handling for Docs, Sheets, Slides, and Drawings so that Google-native files can be exported in the correct format during migration.
{% endhint %}

***

## **2. Configure Drive and GCS Settings**

### Map Get Configs

The next step maps values from your [**DriveConfigFlow** ](/tutorials-1/data-migrations/setting-up-a-google-drive-to-gcs-migration-widget.md#configuration-flow-drive_to_gcs)so the flow has all required tenant and bucket details.<br>

<figure><img src="/files/qK4p8zYkVc8JN2mcjEqM" alt="Data mapping step pulling tenant and bucket details from DriveConfigFlow"><figcaption></figcaption></figure>

### Create Bucket for Tenant

Once these values are ready, you can use the Google Cloud Storage connector to create a **bucket for the tenant** if it doesn’t already exist.

<figure><img src="/files/WZM6f5iX3t2LYehg0UwF" alt="Google Cloud Storage connector step creating a bucket for the tenant"><figcaption></figcaption></figure>

***

## **3. Set the File Path Rules**

You will then hit a **Switch** step that determines how the `filePath` variable is set:

<figure><img src="/files/6EPec8KwObMjxvjEbqQa" alt="Switch step determining how the filePath variable is set"><figcaption></figcaption></figure>

* If `baseFilePath` is provided → set `filePath` = `{{var.baseFilePath}}`

<figure><img src="/files/Vvqu9Ybii0R0JOnuicwc" alt="Setting filePath to baseFilePath when baseFilePath is provided"><figcaption></figcaption></figure>

* If `separateFoldersForUsers` is `true` → set `filePath` per tenant/user

<figure><img src="/files/SNFqFvtOzjo7nZ4vFoSG" alt="Setting filePath per tenant and user when separateFoldersForUsers is true"><figcaption></figcaption></figure>

* Else → set `filePath` = `"Google Drive"`

<figure><img src="/files/gyw9eotUhID4wObUr0Hi" alt="Default case setting filePath to Google Drive"><figcaption></figcaption></figure>

From here, you move into the **Loop Over Input** step.

***

## **4. Loop Over Input Items**

<figure><img src="/files/U4j7edExGGPxcNLm6mcC" alt="Loop Over Input step iterating through the list of file IDs"><figcaption></figcaption></figure>

For each item in your incoming list of file IDs:

* Use the Google Drive connector with **getFile**
  * `File ID` = `{{steps.loopOverInput.loopOverItem.value}}`
  * `param.fields` = `id,name,mimeType,modifiedTime`

<figure><img src="/files/dxCfo1APaDBCdsqIxUGq" alt="Google Drive connector getFile action configured with File ID and fields parameters"><figcaption></figcaption></figure>

* Initialize `fileObject` from `loopOverItem`

<figure><img src="/files/b0TQ4W4Z3UIwwBjFKlMi" alt="Initializing fileObject variable from the loopOverItem value"><figcaption></figcaption></figure>

* Append this file object to the `files` array using the advanced action **insertItem**.

{% hint style="info" %}
You can click the three-dots next to your variable to setup or edit the advanced action selected.
{% endhint %}

<figure><img src="/files/mpP4FwBLMfTgxcGnF2M9" alt="Appending file object to the files array using the insertItem advanced action"><figcaption></figcaption></figure>

***

## **5. Loop Over Files**

After the Loop Over Input ends, the next step will be a loop that runs until all files are processed.

**i. Initialize Loop Counters and Variables**

<figure><img src="/files/1lVdtqG2B7vMfx2aBZcE" alt="Initializing loop counters and variables for file processing"><figcaption></figcaption></figure>

* **Data Mapper:** `fileLength = arrayLength(var.files)` ; total files in the queue.

<figure><img src="/files/OVd9DHBbTFBAbZ7mhHYS" alt="Data mapper setting fileLength to the array length of the files variable"><figcaption></figcaption></figure>

#### Switch Statement

* If no files remain, exit the loop.
* Else, set:

  * `currentFile = {{var.files[0]}}` , the file you’ll process now.

  <figure><img src="/files/JmskP2oYaX71djXQfDhj" alt="Setting currentFile to the first item in the files array"><figcaption></figcaption></figure>

  * Remove the first item from `var.files` using `removeItem`.

<figure><img src="/files/xbKyQ9L2HKa37YdyOTqV" alt="Removing the first item from the files array using removeItem action"><figcaption></figcaption></figure>

**ii. Switch Statement to Check If Current File is a Folder**

<figure><img src="/files/n0LcQJlBjuynzXsqkCTv" alt="Switch step checking if the current file is a folder based on mimeType"><figcaption></figcaption></figure>

* If `currentFile.mimeType` indicates a folder:

  * Call **Google Drive Connector** with action to **getFilesFromFolder** with:

    * `param.q = '{{var.currentFile.file.id}}' in parents`
    * `param.fields = files(id,name,mimeType,modifiedTime)`

    <figure><img src="/files/LcuZBvBePM00ndYpf9kC" alt="Google Drive connector getFilesFromFolder action with parent ID and fields parameters"><figcaption></figcaption></figure>
  * Append each returned file to `var.files` so they’re picked up in the same loop.

  <figure><img src="/files/nOsgwBgcm5Zibzpsl43q" alt="Appending folder contents to the files array for processing in the loop"><figcaption></figcaption></figure>

<figure><img src="/files/LGOpkwdKqAuN89LUKVwb" alt="Loop configuration for processing files within a folder"><figcaption></figcaption></figure>

<figure><img src="/files/MX5vt4HEw5J1XQoxtV0Q" alt="Variable mapping for folder file insertion into the processing queue"><figcaption></figcaption></figure>

**Non-Folder Files**

* Build a **state key** for this file:

<figure><img src="/files/AjS9rJdmsP4zzN29nmzO" alt="Building a state key for the current file to track processing status"><figcaption></figcaption></figure>

* **Read State** for `stateKey` to check if the file is already processed or unchanged.

  <figure><img src="/files/A007OiEzfM2GFcS9g2Pc" alt="Reading state for stateKey to check if the file was already processed"><figcaption></figcaption></figure>

#### iii. Switch Step to Check if Files are Updated

Next Step is a switch statement that checks if files are updated, and ends the flow if there is no update.

<figure><img src="/files/4KG51xYKWCX53ukpx4e4" alt="Switch step checking if files have been updated since last processing"><figcaption></figcaption></figure>

If the file is updated,

* Run **gettingMimeType** JS step → detect MIME type and extension.

```
function handler(params) {
  const mimeTypes = params?.data.var.mimeTypes;
  const fileMimeTypes = params?.data.var.currentFile.file.metadata?.mimeType;

  for (let i = 0; i < mimeTypes.length; i++) {
    if (mimeTypes[i].googleMimeType === fileMimeTypes) {
      return {
        mimeType: mimeTypes[i].exportableMimeTypes,
        extension: mimeTypes[i].exportablExtension
      };
    }
  }
```

* Run **preparingParams** JS step → prepare download/export URLs.

```
function handler(params) {
  const fileId = params?.data.var.currentFile.file.value;
  let fileNamePrefix = '';
  if (params?.data.input.overrideFiles === false) {
    fileNamePrefix = Date.now() + '_';
  }

  return {
    googleUrl: 'https://www.googleapis.com/drive/v3/files/' + fileId + '/export?mimeType=' + params?.data.steps.gettingMimeType.output.mimeType,
    nonGoogleUrl: 'https://www.googleapis.com/drive/v3/files/' + fileId + '?alt=media',
    fileNamePrefix
  };
}
```

* Get access token from **Fastn Connector** using the action **getConnectorToken**.

<figure><img src="/files/SJxnxM1M44RU7Vj2iVG9" alt="Fastn connector getConnectorToken action retrieving an access token"><figcaption></figcaption></figure>

**iv. Decide How to Download (Switch Step)**

<figure><img src="/files/ft0ipPCqEYx54TnfVulz" alt="Switch step deciding download method based on Google-native or non-Google file type"><figcaption></figcaption></figure>

* **If Google-native file (Docs, Sheets, Slides, Drawings):**

  <figure><img src="/files/FrgIrO6LRYOufEVLHIaj" alt="Configuration for downloading Google-native files like Docs, Sheets, and Slides"><figcaption></figcaption></figure>
* **Else (non-Google file):**

  <figure><img src="/files/UVX9bIvsHvrW79Cry9hd" alt="Configuration for downloading non-Google files using direct media URL"><figcaption></figcaption></figure>

**v. Download from Drive**

* For both types of files, the variables that are initialized will connect to the flow component **Download file** where you can download these files.

  <figure><img src="/files/SrJISY9GJ4IT4nJek3U8" alt="Download file flow component that downloads files from Google Drive"><figcaption></figcaption></figure>

**vi. Upload to Google Cloud Storage**

* In the next step, you will use the **Google Cloud Storage** connector with the action **uploadFileToGCS** with your target bucket and `fileName`.

<figure><img src="/files/e8y0VYTpZoi3i0Pu9hhH" alt="Google Cloud Storage connector uploadFileToGCS action with target bucket and fileName"><figcaption></figcaption></figure>

**vii. Update File State**

* In the next step, you will use the State component to overwrite the State for StateKey depending on the updates.

<figure><img src="/files/igNKL9fkji587qnsglVK" alt="State component overwriting the stateKey value after file upload"><figcaption></figcaption></figure>

* Loop picks up next `currentFile` and continues until `var.files` is empty.

***

## **6. Finish the Migration**

The loop continues until all files are processed.\
When complete, the main flow returns a success message confirming the migration.

<figure><img src="/files/lzfczzuKtDxhMee86lFo" alt="Flow returning a success message confirming the migration is complete"><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fastn.ai/tutorials-1/data-migrations/setting-up-a-google-drive-to-gcs-migration-flow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
