Skip to content

feat(hub): add copyFiles API for remote file copy between buckets and repositories#2121

Draft
Wauplin wants to merge 1 commit intomainfrom
cursor/copy-files-api-4d0b
Draft

feat(hub): add copyFiles API for remote file copy between buckets and repositories#2121
Wauplin wants to merge 1 commit intomainfrom
cursor/copy-files-api-4d0b

Conversation

@Wauplin
Copy link
Copy Markdown
Contributor

@Wauplin Wauplin commented Apr 24, 2026

Summary

Implements the "copy files remotely" API in @huggingface/hub, porting the Python HfApi.copy_files functionality to TypeScript/JS.

This enables the "Copy to Bucket" feature on the Hub UI, allowing instant server-side file copy between buckets and from repositories to buckets.

Supported operations

Source Destination Mechanism
Bucket Bucket Server-side copy by xet hash (no data transfer)
Repo (model/dataset/space) with xet files Bucket Server-side copy by xet hash (no data transfer)
Repo with non-xet files (small git files) Bucket Download + re-upload via commit()

Not supported (yet)

  • Bucket → Repo copy
  • Repo → Repo copy

Features

  • copyFiles() — main function, exported from @huggingface/hub
  • parseHfCopyHandle() — parses hf:// handles (buckets, models, datasets, spaces, with @revision support)
  • Single file and recursive folder copy
  • Automatic destination path resolution (file vs directory target)
  • Batched server-side copy via POST /api/buckets/{id}/batch with NDJSON copyFile operations
  • Fallback download+upload path for non-xet repo files using existing commit() infrastructure

Usage

import { copyFiles } from "@huggingface/hub";

// Copy a single file between buckets
await copyFiles({
  source: "hf://buckets/my-bucket/data.bin",
  destination: "hf://buckets/other-bucket/data.bin",
  accessToken: "hf_...",
});

// Copy a folder from a bucket to another bucket
await copyFiles({
  source: "hf://buckets/my-bucket/models/",
  destination: "hf://buckets/other-bucket/backup/",
  accessToken: "hf_...",
});

// Copy from a model repo to a bucket
await copyFiles({
  source: "hf://models/username/my-model/model.safetensors",
  destination: "hf://buckets/my-bucket/",
  accessToken: "hf_...",
});

// Copy an entire dataset to a bucket
await copyFiles({
  source: "hf://datasets/username/my-dataset/",
  destination: "hf://buckets/my-bucket/datasets/",
  accessToken: "hf_...",
});

Reference

Python implementation: huggingface/huggingface_hub#3874

How to test locally

Unit tests (handle parsing)

cd packages/hub
pnpm test -- --testPathPattern copy-files

The parseHfCopyHandle unit tests run without any network access.

Integration tests (require CI Hub access)

The integration tests (copyFiles describe block) run against the CI Hub at https://hub-ci.huggingface.co. They:

  1. Create temporary source/destination repos (bucket and/or model)
  2. Upload test files
  3. Run copyFiles
  4. Verify files appear in the destination
  5. Clean up repos

To run them:

cd packages/hub

# Set up test credentials (the tests use TEST_ACCESS_TOKEN from src/test/consts.ts)
pnpm test -- --testPathPattern copy-files

Manual testing

You can also test manually against the production Hub:

import { copyFiles } from "@huggingface/hub";

// Copy a public model's files to your bucket
await copyFiles({
  source: "hf://models/openai-community/gpt2",
  destination: "hf://buckets/your-username/your-bucket/models/gpt2/",
  accessToken: "hf_YOUR_TOKEN",
});

Slack Thread

Open in Web Open in Cursor 

… repositories

Implements the 'copy files remotely' API in @huggingface/hub, porting the
Python huggingface_hub.HfApi.copy_files functionality to TypeScript/JS.

Supports:
- Bucket-to-bucket copy (server-side, no data transfer)
- Repo (model/dataset/space) to bucket copy
  - xet-backed files: server-side copy by hash
  - non-xet files: download + re-upload via commit
- Single file and recursive folder copy
- hf:// handle parsing with revision support

Reference: huggingface/huggingface_hub#3874

Co-authored-by: Lucain <Wauplin@users.noreply.github.com>
@Wauplin
Copy link
Copy Markdown
Contributor Author

Wauplin commented Apr 24, 2026

closing in favor of @julien-c 's PR to come

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants