# Migrate to Tigris Object Storage

Tigris supports zero-downtime migration from any S3-compatible storage provider using shadow buckets. Data is migrated lazily as it's accessed, so there's no need for a large upfront data transfer. With write-through mode enabled, new writes are synced back to your old bucket, so you can take as long as you need to complete the migration.

## Provider-specific guides[​](#provider-specific-guides "Direct link to Provider-specific guides")

* [Migrate from AWS S3](/docs/migration/aws-s3/.md)
* [Migrate from Google Cloud Storage](/docs/migration/gcs/.md)
* [Migrate from Cloudflare R2](/docs/migration/cloudflare-r2/.md)
* [Migrate from MinIO](/docs/migration/minio/.md)
* [Migrate from any S3-compatible storage](/docs/migration/s3-compatible/.md) (Backblaze B2, DigitalOcean Spaces, Wasabi, Hetzner, Vultr, Linode, and others)

## How shadow bucket migration works[​](#how-shadow-bucket-migration-works "Direct link to How shadow bucket migration works")

Once you've specified your **shadow bucket** (the source S3-compatible bucket), Tigris handles requests so that data is gradually migrated as it is accessed.

This approach works well for large-scale migrations where copying all data at once would be slow or expensive. Instead of migrating everything up front, Tigris fetches objects from the shadow bucket only when requested and copies them into your Tigris bucket asynchronously. Only actively used data is migrated, reducing both latency and cost.

## Write-through mode: migrate at your own pace[​](#write-through-mode-migrate-at-your-own-pace "Direct link to Write-through mode: migrate at your own pace")

Most migration tools force a hard cutover: you copy your data, switch over, and hope nothing breaks. Tigris takes a different approach.

With the optional **write-through** setting enabled, Tigris syncs all new writes back to your original bucket. Your old bucket stays up to date with every new object, update, and delete. This means you can run on Tigris in production while keeping your previous storage provider fully current.

There's no deadline to finish the migration. You can run in write-through mode for days, weeks, or months while you verify that everything works. If you need to roll back, your old bucket has all the latest data. When you're ready, turn off write-through and decommission the old bucket.

Under the hood:

* When an object is requested, Tigris checks its own bucket first. If the object is not found, Tigris fetches it from the shadow bucket, returns it, and asynchronously copies it for future access.
* When uploading an object with write-through enabled, Tigris writes it to both the shadow bucket and the Tigris bucket at the same time, keeping both in sync.
* Objects in the Tigris bucket are stored in the region closest to the user.
* When an object is deleted, it's removed from both the Tigris and shadow buckets.

note

Object listing behavior depends on whether write-through mode is enabled. When write-through is enabled, the list API returns the full contents of the shadow bucket. When write-through is disabled, the list API only includes objects that have already been migrated into Tigris; objects that exist solely in the shadow bucket are not listed until they are accessed and migrated.

## Enable Data Migration[​](#enable-data-migration "Direct link to Enable Data Migration")

Configure the shadow bucket from the Tigris Dashboard or the CLI. See the [provider-specific guides](#provider-specific-guides) above for the exact endpoint, region, and credential format for your source.

* Dashboard
* CLI

To enable data migration from any S3-compatible bucket:

* Go to the [Tigris Dashboard](https://console.storage.dev).
* Click on `Buckets` in the left menu.
* Click on the bucket to which you wish to migrate data.
* Click `Settings`.
* Find the `Enable Data Migration` setting and enable the toggle.
* Provide the access details for your source bucket, or `Shadow Bucket`.

![Shadow bucket migration](/docs/assets/images/shadow-bucket-migration-713141a56e2c7f1c4692e8ea0b111e9d.webp)

If the storage service does not require a region, set the region to `auto`. For example, GCS and Cloudflare R2 use `auto`.

The CLI flow is two commands: configure the shadow source, then optionally drain it.

**1. Configure the shadow bucket** with [`tigris buckets set-migration`](/docs/cli/buckets/set-migration/.md):

```
tigris buckets set-migration my-bucket \

  --bucket source-bucket \

  --endpoint https://<source-endpoint> \

  --region <source-region> \

  --access-key <key> \

  --secret-key <secret>
```

Add `--write-through` to enable write-through mode, or `--disable` to clear the migration configuration.

**2. Actively migrate (optional).** Lazy migration only copies objects when they're accessed. To migrate every remaining object server-side, run [`tigris buckets migrate`](/docs/cli/buckets/migrate/.md):

```
# Migrate every unmigrated object in the bucket

tigris buckets migrate my-bucket



# Migrate only objects under a key prefix

tigris buckets migrate my-bucket/images/
```

The command runs in the foreground and reports progress as it goes.

## Copying object ACLs[​](#copying-object-acls "Direct link to Copying object ACLs")

By default, migrated objects inherit the access control settings of the bucket to which they are migrated. However, if the bucket is configured to [allow object ACLs](/docs/objects/acl/.md#enabling-object-acls), the migration process will copy object ACLs from the shadow bucket to the Tigris bucket. The following rules apply:

* Tigris bucket is private:

  <!-- -->

  * Public S3 objects will be migrated as public and have explicit `public-read` ACL set.
  * Private S3 objects will be migrated as private and inherit bucket ACL.

* Tigris bucket is public:

  <!-- -->

  * Public S3 objects will be migrated as public and inherit bucket ACL.
  * Private S3 objects will be copied as private and have explicit `private` ACL set.
