Current Status
Storage has a first-class CLI command group in Sources/FirestructCLIKit/StorageCommand.swift. It reuses StorageService, so emulator and production URL behavior match the macOS Storage module.
Project Selection
Commands use the selected project from project select unless --project <name|firebaseProjectID|uuid> is passed.
If --bucket is omitted, the CLI defaults to:
<firebaseProjectID>.appspot.com
Live Storage requests can pass either:
--authorization "Bearer <token>"
--access-token <token>
Commands
Bucket discovery:
storage buckets [--bucket fallback-bucket]
Object browsing:
storage list --bucket demo.appspot.com [--prefix avatars/] [--recursive] [--browser]
storage list --bucket demo.appspot.com --browser --sort-by updated --descending
storage inspect --bucket demo.appspot.com --path avatars/alice.png
--browser adds GUI-like folder/file entries built with StorageService.browserEntries.
inspect returns object metadata, preview kind, metadata rows, and the object download URL.
Uploads:
storage upload --bucket demo.appspot.com --file ./avatar.png --path avatars/alice.png --confirm
storage upload --bucket demo.appspot.com --file ./data.json --path imports/data.json --content-type application/json --metadata '{"owner":"alice"}' --confirm
storage upload-folder --bucket demo.appspot.com --folder ./avatars --target avatars --confirm
Downloads:
storage download --bucket demo.appspot.com --path avatars/alice.png --output ./avatar.png
storage download-batch --bucket demo.appspot.com --paths avatars/a.png,avatars/b.png --output-dir ./downloads [--concurrency 4]
storage zip --bucket demo.appspot.com --paths avatars/a.png,avatars/b.png --output ./selection.zip
storage zip-folder --bucket demo.appspot.com --path avatars --output ./avatars.zip
Mutations:
storage delete --bucket demo.appspot.com --path avatars/alice.png --confirm
storage delete --bucket demo.appspot.com --paths avatars/a.png,avatars/b.png --confirm
storage delete-folder --bucket demo.appspot.com --path avatars --confirm
storage copy --bucket demo.appspot.com --path avatars/a.png --target avatars/b.png --confirm
storage move --bucket demo.appspot.com --path avatars/a.png --target archive/a.png --confirm
storage copy-folder --bucket demo.appspot.com --path avatars --target avatars-copy --confirm
storage move-folder --bucket demo.appspot.com --path avatars --target archive/avatars --confirm
storage rename-folder --bucket demo.appspot.com --path avatars --name archived-avatars --confirm
storage duplicate-folder --bucket demo.appspot.com --path avatars --confirm
URL helpers:
storage url --bucket demo.appspot.com --path avatars/alice.png
storage signed-url --bucket demo.appspot.com --path avatars/alice.png --expires 3600
storage signed-url --bucket demo.appspot.com --path avatars/alice.png --expires 3600 --service-account-file ./service-account.json
For emulator projects, signed-url returns a deterministic emulator download URL with the requested expiration. For production projects, V4 signing requires --service-account-file.
Safety
- Upload, delete, copy, move, folder upload, folder delete, folder copy, folder move, folder rename, and folder duplicate require
--confirm. - Read-only project links reject Storage mutations.
- Folder copy/move checks for nested targets and duplicate destination objects before mutating.
- Object copy/move validates that source and target paths differ.
- Long multi-object operations run through
TaskOrchestratorand return task status, counters, duration, and errors in JSON output.
Output
All commands emit JSON. Long-running commands include a task object:
{
"status": "success",
"processedOperations": 2,
"totalOperations": 2,
"attemptCount": 1
}
Source Anchors
Sources/FirestructCLIKit/StorageCommand.swiftSources/FirestructCLIKit/FirestructCLI.swiftSources/FirestructCLIKit/JSONOutput.swiftSources/FirestructCore/StorageService.swiftTests/FirestructCLIIntegrationTests/FirestructCLIIntegrationTests.swift