Skip to main content

Goal

Move a provider library into Assets with deterministic folder mapping, checksum evidence, restart-safe progress, and an item-level audit report.

Prerequisites

  • A verified Cloudinary, S3-compatible, or native S2 source connection
  • A destination Assets bucket and its UUID
  • An assets:process token to start, cancel, or retry and assets:read to inspect or download reports
  • An assets:admin token to discover Cloudinary project folders and manage source connections

Workflow

1
Run a dry migration with the intended source prefix and conflict policy.
2
Wait for inventory to complete, then inspect summary counts and the JSON or CSV item report.
3
Start a non-dry migration with the same mapping once duplicate, conflict, unsupported-object, and pending-checksum outcomes are acceptable.
4
Follow persisted phase, item, and byte counters. Cancel cooperatively or retry only terminal failed items when needed.
5
Retain the report as migration evidence and verify a sample of imported assets through StackShift CDN URLs.

Assets storage and import access

A source connection authorizes reading your existing provider. It does not provision external storage. Choose a managed Assets bucket to use your existing Assets storage allowance; no S2 bucket or separate S2 purchase is required. Imported files count toward your Assets storage allowance. Make sure you have enough available storage before starting. Your bucket’s file restrictions, malware scanning, and access settings also apply to imports.

Import separate projects from Cloudinary

In Assets Operations, open Migrations and choose Import project folders. Select a verified Cloudinary connection to discover its top-level folders. Each project has its own destination bucket name; nested folders remain inside that bucket. Run inventory for each project and review its report before choosing Import project. Inventory creates a private destination bucket if it does not exist, but does not copy files. An existing bucket keeps its access settings. Importing skips existing file keys. For example, sabilytics/images/logo.png becomes images/logo.png in the sabilytics bucket. Open the bucket and use Organize to browse its folders and view their assets. Identical files in different projects or paths remain separate entries. Private images use authenticated library previews; viewing a thumbnail does not publish the file or change its visibility. Images still undergoing checks or blocked by policy remain unavailable. API clients can list top-level folders with GET /api/v1/assets/connections/{connectionID}/folders, then create a bucket and start a migration with that folder as source_prefix for each project. Files at the Cloudinary root are not included in the project-folder list. Import those separately using Start migration. If a folder name is not a valid bucket name, choose a destination name before running inventory.

What discovery preserves

  • Cloudinary: in fixed folder mode, paths come from public IDs. In dynamic folder mode, paths come from the asset folder and the final public-ID segment; nested and empty folders are preserved. Tags, context, structured metadata, resource type, source URL, and source identity remain in migration evidence.
  • Cloudinary imports originals only. StackShift regenerates transforms, thumbnails, video outputs, and other derivatives under the destination bucket policy.
  • S3-compatible and S2: recursive objects beneath source_prefix; relative keys preserve folder structure, and content type, cache control, object metadata, object tags, size, provider checksum when available, and source identity are recorded.
  • Discovery is paginated and idempotent by (migration, source_identity), so worker restarts do not duplicate inventory rows.

Create Cloudinary and S2 source connections

Cloudinary configuration keeps the cloud name and API key as non-secret connection data and encrypts the API secret. A native S2 import source is a stackshift_s2 connection that references an owned bucket UUID and carries no credentials.

Dry-run semantics

A dry run finishes after inventory. It may issue list and metadata/tag reads, but it does not download objects just to manufacture a missing checksum and does not create assets. The item report is the source of truth for what was and was not knowable before execution.
  • duplicate_checksum: a known SHA-256 matches an asset at the same destination bucket and path.
  • key_conflict: the destination bucket already contains the proposed logical key.
  • unsupported_object: the known size or MIME type violates destination bucket policy.
  • pending_execution: checksum evidence requires streaming the object during the real run.
  • inventory_lookup_failed: StackShift could not safely classify an item and records an error instead of guessing.

Start and follow a migration

Checksum deduplication and key conflicts

  • Execution streams the source through bounded scratch space and calculates SHA-256 before asset commit.
  • Deduplication reuses matching content only at the same destination bucket and path. Identical files at different paths or in different project buckets remain separate assets.
  • skip is the default conflict policy and preserves the existing logical asset.
  • new_version replaces the compatible existing logical asset through revision-aware versioning. Exact normalized MIME compatibility is required.
  • rename appends the first eight hex characters of the source-identity SHA-256 before the extension, then a stable numeric suffix if that name is also occupied.

Reconciliation and safe cutover

JSON migration reports include a reconciliation summary. It counts discovered, imported, skipped, failed, canceled, unresolved and mapped items, verified and missing checksums, and warning codes. A completed dry run can reconcile inventory while transfer items remain unresolved. inventory_reconciled means the completed inventory count matches the report and, for a real import, every item has a terminal transfer outcome. Failed or skipped items still need review. delivery_verified and cutover_ready remain false because this report does not perform or retain an application delivery test. Transfer completion and a known provider checksum do not establish usable destination delivery. Before cutover, save the report; resolve each omission and conflict; compare source-to-destination identities and verified checksums; check required metadata and private access; then exercise the actual image, video and publication URLs your application will use. Test anonymous denial for restricted originals and video child resources, as well as authorized access. Compare transformation outputs visually: provider URLs and transform syntax are not interchangeable. Keep the source library and previous application configuration. Roll back application references first if verification fails. Do not bulk-delete mapped destination IDs: skipped duplicates may refer to assets that existed before the migration. Imports using new_version require a separate revision-aware restore of the previous version after checking retained review and publication references. Source deletion is never part of this migration workflow.

Progress, retries, cancellation, and reports

  • Migration states are queued, running, completed, failed, and canceled; phases begin at inventory, continue through transfer, and finish at complete.
  • Persisted counters include total/processed/imported/skipped/failed items and total/processed bytes. They remain available independently of the worker process.
  • Each item stores attempt count, maximum attempts, checksum state, mapped asset, warning/error code and message, timestamps, and source/destination identity. Automatic transfer retries use bounded backoff.
  • Cancellation is cooperative: active work stops, unclaimed items become canceled, incomplete multipart work is aborted, and scratch data is removed. Start a new migration to continue a canceled migration.
  • JSON contains the complete migration and item objects. CSV columns are source_identity, source_key, destination_key, status, checksum_sha256, mapped_asset_id, warning_code, error_code, and error_message.

Expected result

Every discovered source identity ends in an imported, skipped, failed, or canceled item with checksum and mapped-asset evidence where available.

Common failures

  • The source connection is not verified or lost provider permissions after verification.
  • A dry run reports pending_execution; the source did not expose SHA-256 and the dry run intentionally did not download bytes.
  • new_version skips a key conflict because the existing and incoming normalized MIME types are incompatible.
  • A worker or provider interruption exhausts automatic attempts; retry the specific failed item after fixing the cause.

Storage connections, BYOB, and StackShift S2

Configure AWS S3, Cloudflare R2, Wasabi, MinIO, generic S3, or native StackShift S2 without exposing customer storage credentials or changing delivery URLs.

Assets platform API, SDK, CLI, and operations

A complete interface and recovery reference for storage connections, S2, imports, relocation, OCR, browser capabilities, reports, scopes, events, billing, and durable worker behavior.

Upload UX and DAM

Build a durable upload and digital-asset-management workflow with resumable sessions, revision-safe mutations, search, collections, webhooks, and usage summaries.