| name | mpremote File Transfer |
| description | Use this skill when copying files to or from a MicroPython device using mpremote. Covers file copy syntax, directory operations, and best practices for device filesystem management. Triggers on "copy file to device", "upload to device", "download from device", "mpremote fs", "device filesystem", "copy firmware files". |
File Transfer with mpremote
Basic copy operations
Copy a local file to the device:
mpremote <device> resume fs cp local_file.py :remote_file.py
Copy from device to host:
mpremote <device> resume fs cp :remote_file.py local_file.py
The colon prefix : denotes a device path. Without it, the path is local.
Device path syntax
:filename.py - file in the device's current directory (root)
:/path/to/file - absolute path on device
:data/1.data - relative path on device
Always use resume
mpremote <device> resume fs cp file.py :file.py
mpremote <device> fs cp file.py :file.py
Without resume, mpremote performs a soft reset before the filesystem operation, restarting the application and potentially losing state.
Device identification
Use mpy-dev to resolve device labels to stable serial paths:
mpremote connect $(mpy-dev tty my-board) resume fs cp file.py :file.py
mpremote connect /dev/serial/by-id/usb-FTDI_TTL232RG-VREG1V8_FT55TKQB-if00-port0 resume fs cp ...
mpremote u0 resume fs cp ...
Install mpy-dev with uv tool install git+https://gitlab.com/alelec/mpy-dev.git if not available. See the device-interaction skill for full mpy-dev usage.
Directory operations
List files:
mpremote <device> resume fs ls :
mpremote <device> resume fs ls :data/
Create directory:
mpremote <device> resume fs mkdir :data
Remove file:
mpremote <device> resume fs rm :device_override.py
Remove directory (must be empty):
mpremote <device> resume fs rmdir :old_dir
Recursive file tree:
mpremote <device> resume fs tree
Copying multiple files
mpremote processes one operation per invocation. For multiple files, use a shell loop:
for f in *.py; do
mpremote <device> resume fs cp "$f" ":$f"
sleep 0.5
done
The sleep is important - mpremote holds the serial port during the copy, and the next invocation needs it released.
Large file transfers
For files >50KB, the transfer takes several seconds. mpremote uses the raw REPL protocol for fs cp, which sends Ctrl+C on entry. On asyncio/aiorepl devices, this can crash the event loop.
For large transfers to asyncio devices, consider:
- Transfer while the device is in a safe state (e.g. on dock, not collecting data)
- Accept that the transfer may restart the application
- Use the persistent PTY session approach for very large batch transfers
Filesystem capacity
Check available space from the device:
mpremote <device> resume exec "import os; print(os.statvfs('/'))"
The result tuple fields: (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax). Available bytes = bsize * bfree.
Common patterns
Deploy a Python module override
mpremote <device> resume fs cp device_override.py :device_override.py
mpremote <device> resume fs ls :
mpremote <device> resume exec "import machine; machine.reset()"
Back up device data
mpremote <device> resume fs ls :data/
mkdir -p backup/data
for f in $(mpremote <device> resume fs ls :data/ | awk '{print $NF}'); do
mpremote <device> resume fs cp ":data/$f" "backup/data/$f"
sleep 0.5
done
Clean device filesystem
mpremote <device> resume fs rm :device_override.py
mpremote <device> resume exec "
import os
for f in os.listdir('data'):
os.remove('data/' + f)
print('removed', f)
"
Troubleshooting
"failed to access" errors: Another process holds the serial port. Check with fuser /dev/serial/by-id/<device-id> and kill stale processes.
Transfer seems to hang: Large files take time. A 70KB file takes ~3 seconds. Don't interrupt - partial writes corrupt the filesystem.
File appears but content is wrong: The device may have a filesystem cache. After writing, either reboot or call os.sync() from the REPL.