-
Notifications
You must be signed in to change notification settings - Fork 11
Folder Management
Comprehensive guide to managing folders in R2 buckets.
R2-Manager-Worker provides full folder management capabilities built on top of R2's flat object storage structure. Folders are represented by object key prefixes with / delimiters, similar to how AWS S3 handles folders.
Key Features:
- 📁 Create folders with placeholder
.keepfiles - ✏️ Rename folders (batch copy + delete operations)
- 📋 Copy folders between buckets and to folders within buckets (v1.3.0)
- 🔄 Move folders between buckets and to folders within buckets (v1.3.0)
- 🗑️ Delete folders and all contents
- 🧭 Breadcrumb navigation for folder hierarchy
- 👁️ Visual folder display with distinct icons
R2 uses a flat object storage model (like AWS S3). Folders don't exist as separate entities - they're created by using / characters in object keys:
my-bucket/
├── images/photo1.jpg (key: "images/photo1.jpg")
├── images/photo2.jpg (key: "images/photo2.jpg")
└── documents/report.pdf (key: "documents/report.pdf")
The Worker uses R2's delimiter parameter to detect folders:
// List request with delimiter=/
const response = await bucket.list({
delimiter: "/",
prefix: "images/",
});
// Returns:
// - objects: Files directly in the prefix
// - delimitedPrefixes: Folder paths (e.g., ["images/subfolder/"])When you create a folder, the application creates a .keep placeholder file:
my-folder/
└── .keep (0 bytes)
This ensures the folder exists even when empty. The .keep file is automatically created and can be safely deleted once other files are added.
- Navigate to a bucket
- Click 📁 Create Folder button
- Enter folder name
- Click Create Folder
Folder Name Rules:
- Letters (a-z, A-Z), numbers (0-9), hyphens (-), underscores (_), forward slashes (/)
- Cannot start or end with
/ - Cannot contain consecutive slashes (
//) - Use
/for nested folders (e.g.,parent/child/grandchild)
POST /api/folders/:bucketName/create
Content-Type: application/json
{
"folderName": "my-folder"
}Example with nested folders:
{
"folderName": "documents/2025/reports"
}Response:
{
"success": true,
"folderPath": "documents/2025/reports/"
}The UI provides breadcrumb navigation showing your current location:
🏠 Root › documents › 2025 › reports
- Click any breadcrumb to navigate to that level
- Click 🏠 Root to return to bucket root
- Current location is highlighted and non-clickable
Folders appear above files in the grid view:
📁 documents/ Folder
📁 images/ Folder
📄 readme.txt 2.5 KB Mar 1, 2025
📄 config.json 1.2 KB Feb 28, 2025
- Click a folder to navigate into it
- Folders show "Folder" instead of file size
- Distinct folder icon (📁) vs file icons
Rename a folder by updating all object keys with the folder prefix.
- Right-click on a folder in grid or list view
- Select ✏️ Rename from the context menu
- Enter the new folder name in the modal dialog
- Press Enter or click Rename button
- Folder and all contents are renamed
Validation:
- Cannot be empty
- Only letters, numbers, hyphens, underscores, and forward slashes allowed
- Cannot start or end with
/ - Cannot contain consecutive slashes (
//) - Checks if folder with new name already exists
Features:
-
Keyboard Shortcuts:
-
Enter- Submit rename -
Escape- Cancel rename
-
- Real-time Feedback - Instant validation as you type
- Progress Tracking - See how many files are being renamed
PATCH /api/folders/:bucketName/rename
Content-Type: application/json
{
"oldPath": "old-folder",
"newPath": "new-folder"
}Response:
{
"success": true,
"copied": 45,
"failed": 0
}Process:
- Lists all objects with
oldPathprefix - Copies each object to
newPathprefix - Deletes original objects
- Processes in batches of 100 with 300ms delays
Important Notes:
- All nested folders and files are renamed
- Metadata is preserved during copy
- Large folders may take time to rename
- Operation cannot be undone
Copy a folder and all its contents to another bucket or to a folder within the same/different bucket (v1.3.0).
- Select one or more folders
- Click Transfer dropdown
- Select Copy to...
- Choose destination bucket
-
NEW: Optionally enter a destination folder path (e.g.,
backups/2024) - Click Copy Files
Source folder remains unchanged.
- ✅ Same-Bucket Copies - Create folder duplicates within the same bucket
- ✅ Folder Targeting - Copy to specific folder locations
- ✅ Path Input - Enter destination folder path like
archives/backups - ✅ Root Transfer - Leave path empty to copy to bucket root
POST /api/folders/:sourceBucket/:folderPath/copy
Content-Type: application/json
{
"destinationBucket": "target-bucket",
"destinationPath": "optional/destination/folder"
}URL Parameters:
-
:sourceBucket- Source bucket name -
:folderPath- Folder path to copy (URL-encoded)
Request Body:
-
destinationBucket(required) - Target bucket name -
destinationPath(optional) - Destination folder path- Leave empty to copy to bucket root with source folder name
- Specify path to copy folder to specific location
Response:
{
"success": true,
"copied": 120,
"failed": 2
}Examples:
# Copy 'images' folder to different bucket (preserves folder name)
POST /api/folders/bucket-a/images/copy
{"destinationBucket": "bucket-b"}
# Result: bucket-b/images/... (all contents copied)
# Copy 'images' folder to specific location in different bucket
POST /api/folders/bucket-a/images/copy
{"destinationBucket": "bucket-b", "destinationPath": "backups/2024/images"}
# Result: bucket-b/backups/2024/images/...
# Copy folder to another folder within same bucket
POST /api/folders/my-bucket/reports/copy
{"destinationBucket": "my-bucket", "destinationPath": "archives/reports"}
# Result: my-bucket/archives/reports/... (duplicate created)Process:
- Lists all objects with folder prefix in source bucket
- For each object:
- Fetches from source
- Uploads to destination with new path
- Source folder remains unchanged
- Processes in batches with rate limiting
Important Notes:
- Same-bucket copies are allowed when
destinationPathdiffers from source - Allows creating folder duplicates within a bucket at different paths
- Source folder structure is preserved in destination
Move a folder and all its contents to another bucket or to a folder within the same/different bucket (v1.3.0).
- Select one or more folders
- Click Transfer dropdown
- Select Move to...
- Choose destination bucket
-
NEW: Optionally enter a destination folder path (e.g.,
archives/old) - Click Move Files
Source folder is removed after successful move.
- ✅ Same-Bucket Moves - Reorganize folders within the same bucket
- ✅ Folder Targeting - Move to specific folder locations
- ✅ Path Input - Enter destination folder path like
processed/incoming - ✅ Root Transfer - Leave path empty to move to bucket root
POST /api/folders/:sourceBucket/:folderPath/move
Content-Type: application/json
{
"destinationBucket": "target-bucket",
"destinationPath": "optional/destination/folder"
}URL Parameters:
-
:sourceBucket- Source bucket name -
:folderPath- Folder path to move (URL-encoded)
Request Body:
-
destinationBucket(required) - Target bucket name -
destinationPath(optional) - Destination folder path- Leave empty to move to bucket root with source folder name
- Specify path to move folder to specific location
Response:
{
"success": true,
"moved": 85,
"failed": 1
}Examples:
# Move 'temp' folder to different bucket
POST /api/folders/bucket-a/temp/move
{"destinationBucket": "bucket-b"}
# Result: bucket-b/temp/... (bucket-a/temp/ is deleted)
# Move 'drafts' folder to specific location in different bucket
POST /api/folders/bucket-a/drafts/move
{"destinationBucket": "bucket-b", "destinationPath": "archives/2024/drafts"}
# Result: bucket-b/archives/2024/drafts/... (bucket-a/drafts/ is deleted)
# Move folder to another folder within same bucket
POST /api/folders/my-bucket/incoming/move
{"destinationBucket": "my-bucket", "destinationPath": "processed/incoming"}
# Result: my-bucket/processed/incoming/... (my-bucket/incoming/ is deleted)Process:
- Copies all objects to destination (same as copy operation)
- Deletes all objects from source folder
- Source folder is removed after successful move
Important Notes:
- Same-bucket moves are allowed when
destinationPathdiffers from source - Allows reorganizing folders within a bucket
- This is a copy + delete operation
- If copy succeeds but delete fails, you may have duplicates
- Cannot be undone
- Large folders may take significant time
Delete a folder and optionally all its contents.
- Navigate to parent folder
- Select the folder (checkbox or click)
- Click Delete Selected
- Confirm deletion
Check folder contents (safe mode):
DELETE /api/folders/:bucketName/:folderPathForce delete (delete all contents):
DELETE /api/folders/:bucketName/:folderPath?force=trueResponse without force (folder contains files):
{
"success": false,
"fileCount": 45,
"message": "Folder contains files. Use force=true to delete."
}Response with force:
{
"success": true,
"deleted": 45
}Process:
- Lists all objects with folder prefix
- Counts total files
- If
force=falseand files exist, returns file count - If
force=true, deletes all objects in batches - Rate limiting applied (300ms between batches)
Safety Features:
- Two-step confirmation in UI
- Requires explicit
force=truefor non-empty folders - Reports number of files that will be deleted
All folder operations process objects in batches to avoid rate limits:
Batch Size: 100 objects per request
Rate Limiting: 300-500ms delay between batches
Progress Tracking: Returns success/failure counts
Small folders (<100 files): < 1 second
Medium folders (100-500 files): 1-5 seconds
Large folders (500-1000 files): 5-15 seconds
Very large folders (>1000 files): May take several minutes
Tips for large folders:
- Operations run in the background
- Progress is reported via response
- Monitor Worker logs for detailed progress
- Consider chunking very large moves/copies
Valid Characters:
- Letters:
a-z,A-Z - Numbers:
0-9 - Special:
-(hyphen),_(underscore),/(forward slash)
Invalid Patterns:
- Leading slash:
/folder - Trailing slash:
folder/(automatically added) - Consecutive slashes:
folder//subfolder - Empty names
Valid Examples:
images
documents/2025
my-folder_v2
reports/Q1/final-draft
Invalid Examples:
/images (leading slash)
my folder (space not allowed)
docs//2025 (consecutive slashes)
files\reports (backslash not allowed)
The UI validates folder names in real-time:
- ✅ Green checkmark for valid names
- ❌ Red error message for invalid names
- Automatic
.keepfile creation - Path normalization
-
Use descriptive names:
user-uploadsnottemp - Consistent naming: Use hyphens or underscores, not both
-
Date-based folders:
2025/01for time-series data -
Hierarchical structure:
projects/client-name/documents
- Avoid deep nesting: Keep folder depth under 5 levels
- Batch similar operations: Move/copy multiple folders together
- Monitor large operations: Check Worker logs for progress
- Use meaningful prefixes: Helps with listing and filtering
-
Clean up empty folders: Delete unnecessary
.keepfiles - Consolidate folders: Merge related folders periodically
- Document structure: Maintain a folder structure guide
- Regular audits: Review and reorganize folder hierarchy
Cause: No objects with that prefix
Solution: Create a file or .keep placeholder in the folder
Cause: Large number of objects
Solution:
- Wait for operation to complete
- Check Worker logs for progress
- Consider breaking into smaller operations
Cause: force=true not set
Solution: Add ?force=true query parameter
Cause: Rate limiting or API errors
Solution:
- Check Worker logs for specific errors
- Retry operation
- Verify source bucket permissions
Cause: Invalid characters or patterns
Solution:
- Use only letters, numbers, hyphens, underscores, slashes
- Remove leading/trailing slashes
- Fix consecutive slashes
| Status Code | Description |
|---|---|
200 OK |
Operation succeeded |
400 Bad Request |
Invalid folder name or parameters |
404 Not Found |
Bucket or folder not found |
500 Internal Server Error |
Operation failed (check logs) |
- API Reference - Complete endpoint documentation
- File Operations - Managing individual files
- Bucket Management - Working with buckets
- Cloudflare R2 Object Keys - Understanding R2's flat structure
📝 Note: Folder operations are batch processes that may take time for large folders. Always monitor operation results and check logs for detailed progress information.
- Home - Documentation overview
- Quick Start Guide - Get up and running in minutes
- Installation & Setup - Complete deployment guide
- Configuration Reference - Environment variables and settings
- Upgrade Guide - Database schema migrations
- Bucket Management - Create, rename, delete buckets
- Object Lifecycles - Automate expiration and IA transitions ⭐ NEW
- Local Uploads - Faster uploads via nearby edge storage ⭐ NEW
- Job History - Track bulk operations with audit trail ⭐ NEW
- Webhooks - Configure HTTP notifications for events ⭐ NEW
- AI Search - Semantic search with Cloudflare AI
- S3 Import - Migrate from AWS S3 to R2 ⭐ NEW
- Cross-Bucket Search - Search across all buckets with filters
- File Operations - Upload, download, move, copy, delete files
- Folder Management - Organize files hierarchically
- Signed URLs & Sharing - Generate secure shareable links
- Advanced Filtering - Filter by extension, size, and date
- Development Guide - Local setup and development workflow
- API Reference - Complete endpoint documentation
- Architecture Overview - Technical stack and design
- Authentication & Security - Zero Trust implementation
- JWT Validation - JWT token validation and verification
- Troubleshooting - Common issues and solutions
- FAQ - Frequently asked questions
- Roadmap - Planned features and enhancements