A fast, reliable Rust CLI tool for uploading files to Dropbox with concurrent uploads, automatic OAuth token refresh, and folder watching for background sync.
✨ Core Upload
- Upload single files or entire directories
- Concurrent uploads (configurable parallelism)
- Automatic chunked upload for large files (≥150MB)
- Progress tracking and error reporting
🔐 Smart Authentication
- OAuth 2.0 with automatic token refresh
- Secure token storage in
~/.dbxup_tokens - No manual token management needed
👁️ Watch Mode (NEW)
- Monitor folders and auto-upload new files
- Run as background daemon/service
- Auto-reload config file when modified (no restart needed!)
- Robust handling of folder deletion/recreation
- Event debouncing to avoid duplicate uploads
cargo build --releaseThe binary will be at ./target/release/dbxup
Export your Dropbox app credentials:
export DROPBOX_APP_KEY="your_app_key_here"
export DROPBOX_APP_SECRET="your_app_secret_here"Run the auth command:
./target/release/dbxup auth --app-key $DROPBOX_APP_KEY --app-secret $DROPBOX_APP_SECRETThis opens a browser for authorization. Copy the code and paste it back into the terminal. Your refresh token will be saved for future use.
Single file:
./target/release/dbxup --file /path/to/file.txt --destination /UploadsEntire directory:
./target/release/dbxup --dir /path/to/folder --destination /BackupsWith custom parallelism:
./target/release/dbxup --dir /path/to/folder --destination /Backups --parallel 10Set up OAuth credentials with automatic refresh:
dbxup auth --app-key <KEY> --app-secret <SECRET>This is a one-time setup. The tool will automatically refresh access tokens as needed.
If you already have a refresh token:
dbxup setup --app-key <KEY> --refresh-token <TOKEN>Auto-upload new files from monitored folders:
Using config file (recommended):
dbxup watch --config watch-config.jsonUsing command-line:
dbxup watch \
--folders /local/path:/dropbox/path \
--folders /another/path:/another/dest \
--parallel 5 \
--debounce 2000See WATCH_MODE.md for detailed documentation.
Remove saved OAuth credentials:
dbxup logoutdbxup [OPTIONS]
OPTIONS:
-t, --token <TOKEN> Dropbox access token (or use DROPBOX_ACCESS_TOKEN)
--app-key <KEY> Dropbox app key (or use DROPBOX_APP_KEY)
--app-secret <SECRET> Dropbox app secret (or use DROPBOX_APP_SECRET)
-f, --file <FILE> Upload a single file
-d, --dir <DIR> Upload a directory (all files recursively)
-o, --destination <PATH> Dropbox destination folder [default: /]
-p, --parallel <N> Number of concurrent uploads [default: 5]
--chunk-size <MB> Chunk size in MB for large files [default: 8]
-v, --verbose Enable verbose logging
-h, --help Print help
dbxup watch [OPTIONS]
OPTIONS:
-c, --config <FILE> Config file with folders to watch (JSON)
-f, --folders <PATH:PATH>... Folders to watch (format: /local:/dropbox)
-p, --parallel <N> Number of concurrent uploads
--debounce <MS> Debounce delay in milliseconds
Add to ~/.bashrc or ~/.zshrc:
export DROPBOX_APP_KEY="your_app_key_here"
export DROPBOX_APP_SECRET="your_app_secret_here"Create watch-config.json:
{
"folders": [
{
"local_path": "/home/user/Documents",
"dropbox_path": "/Backup/Documents",
"description": "Auto-backup documents"
},
{
"local_path": "/var/log/myapp",
"dropbox_path": "/Logs/myapp",
"description": "Application logs"
}
],
"settings": {
"parallel_uploads": 5,
"debounce_ms": 2000
}
}See watch-config.example.json for a complete example.
dbxup --dir ~/Pictures/2024 --destination /Photos/2024 --parallel 10dbxup --dir ./dist --destination /Archive/builds/$(date +%Y%m%d)# Files ≥150MB automatically use chunked upload
dbxup --file ./large-video.mp4 --destination /Videos --chunk-size 8# Set up once
dbxup auth
# Create config
cat > watch-config.json <<EOF
{
"folders": [
{"local_path": "/home/user/Documents", "dropbox_path": "/Backups/Documents"}
],
"settings": {
"parallel_uploads": 5,
"debounce_ms": 3000
}
}
EOF
# Run in background
dbxup watch --config watch-config.jsonSee WATCH_MODE.md for complete systemd setup instructions.
- Initial Setup: Run
dbxup authto get a refresh token via OAuth - Token Storage: Refresh token saved in
~/.dbxup_tokens - Automatic Refresh: On each upload, tool checks if access token needs refresh
- Seamless: No manual intervention required after initial setup
- Small files (<150MB): Single API call using
files/upload - Large files (≥150MB): Chunked upload using upload session API
- Start session with first chunk
- Append remaining chunks (8MB default)
- Finalize session
Uses tokio::sync::Semaphore to limit concurrent uploads:
- Prevents overwhelming the API
- Controls network bandwidth usage
- Configurable with
--parallelflag
- File System Monitoring: Uses
notifycrate for efficient file watching - Event Debouncing: Waits for debounce period to avoid partial uploads
- Folder Resilience: Automatically re-watches folders that appear/reappear
- Concurrent Uploads: Multiple files uploaded in parallel (configurable)
dbxup/
├── src/
│ ├── main.rs # CLI entry point, command routing
│ ├── config.rs # Configuration validation
│ ├── error.rs # Error types
│ ├── oauth.rs # OAuth flow, token refresh
│ ├── token_storage.rs # Token persistence
│ ├── retry.rs # Retry logic with backoff
│ ├── upload_manager.rs # Concurrent upload orchestration
│ ├── watcher.rs # Folder watching daemon
│ ├── dropbox/
│ │ ├── client.rs # Dropbox API client wrapper
│ │ └── upload.rs # Upload logic (simple & chunked)
│ └── files/
│ ├── scanner.rs # Directory traversal
│ └── metadata.rs # File metadata, path mapping
├── Cargo.toml
├── README.md
├── WATCH_MODE.md # Detailed watch mode docs
├── watch-config.example.json
└── dbxup-watch.service # systemd service template
- Network Errors: Automatic retry with exponential backoff
- Rate Limiting: Respects
Retry-Afterheaders - Auth Errors: Clear messages with instructions
- File Errors: Continues with other files, reports failures at end
- Token Expiry: Automatic refresh (transparent to user)
- Speed: Concurrent uploads maximize throughput
- Memory: Efficient streaming for large files
- Network: Connection pooling, automatic retry
- CPU: Minimal overhead when watching folders
- Max file size: 350GB (Dropbox API limit)
- No deletion sync: Watch mode only uploads new files
- One-way sync: Local → Dropbox (no bidirectional sync)
- No conflict resolution: Last upload wins
Run dbxup auth to set up OAuth credentials first.
Your access token expired. The tool should automatically refresh, but if it fails:
dbxup logout
dbxup auth # Re-authenticateCheck that:
- File/directory exists
- You have read permissions
- Path is correct (use absolute paths if unsure)
Ensure environment variables are set:
export DROPBOX_APP_KEY="..."
export DROPBOX_APP_SECRET="..."- Check logs:
journalctl --user -u dbxup-watch -f(if using systemd) - Verify files aren't hidden (starting with
.) - Confirm debounce period has passed (default: 2s)
cargo buildcargo testexport RUST_LOG=debug
cargo run -- --verbose --file test.txt --destination /- clap: CLI parsing
- tokio: Async runtime
- reqwest: HTTP client
- dropbox-sdk: Dropbox API
- notify: File system watching
- walkdir: Directory traversal
- thiserror: Error handling
- serde/serde_json: Configuration parsing
This project is provided as-is for personal use.
This is a personal tool, but suggestions and improvements are welcome!
For Dropbox API issues, see: https://www.dropbox.com/developers/documentation
For app key/secret setup:
- Go to https://www.dropbox.com/developers/apps
- Create an app
- Generate app key and secret
- Add redirect URI:
http://localhost:8888/oauth/callback(for local OAuth)