A fast, minimal desktop app for importing and organizing photos from SD cards. Review every shot before it lands on your drive - tag, move, and delete in one pass.
Think of it as a lightweight, free take on the pro ingest workflow: cull on the card, move (not copy) with verification, and land everything date-organized on your disk.
- Auto-detects SD cards - plugging in a card surfaces it instantly as a source option
- Visual review grid - browse all photos as thumbnails, grouped by date, before committing to anything
- Full-resolution preview with pixel inspection - click any photo for a lightbox with EXIF details and keyboard navigation; scroll to zoom, drag to pan, double-click for a 1:1 pixel view. Neighboring photos are prefetched so arrow-key browsing doesn't wait on the card
- Full-size RAW previews - CR2/CR3/NEF/ARW/DNG show the full-resolution JPEG embedded by the camera (extracted straight from the file header, no RAW decoding), same as RAF
- Tag-based workflow - mark each photo as Transfer, Delete, or leave it untagged; filter the grid by any tag; shift-click or drag to multi-select
- Verified moves - every copy is checked against the source before the original is deleted; a failed copy never costs you a photo
- Safe deletes - rejects aren't erased: they're moved (verified, too) into a
_Rejects/folder on the destination drive, so a mis-tag at 2am is always recoverable. True deletion is an opt-in toggle. Library-mode deletes go to the OS trash. - Auto-organizes by date - photos land in
Destination/YYYY/Month/filename.jpg(optionally by day); files without a date go toUnsorted/ - True duplicate detection - files already at the destination are compared by content, not just name and size; real duplicates are skipped, same-name-different-content files are renamed
IMG_0001_1.jpg,_2, … - RAW-aware - reads EXIF from CR2/CR3/NEF/ARW/RAF/ORF/RW2/DNG, extracts embedded thumbnails without decoding the full file, and can separate RAW files into their own subfolder
- Live transfer progress - byte-level progress bar with current file name, plus a transferred / skipped / error summary
- Persistent config - source, destination, and options are remembered between sessions
There is also an experimental Library mode for browsing, star-rating, and pruning an existing photo folder.
Runs on Windows, macOS, and Linux. SD cards are auto-detected on all three (Windows removable drives, macOS /Volumes, Linux /media and /run/media); anything with a DCIM folder is flagged as a camera card.
Prebuilt binaries are on the Releases page:
| Platform | File |
|---|---|
| Windows | photomover-<version>-setup.exe |
| macOS | photomover-<version>.dmg |
| Linux | photomover-<version>.AppImage or .deb |
macOS builds are unsigned - on first launch, right-click the app and choose Open.
| Setup | Review |
|---|---|
| Full-resolution preview | Done |
|---|---|
Photos are organized automatically by the date taken from EXIF metadata (falling back to the file's modification date):
Destination/
├── 2024/
│ ├── April/
│ │ ├── IMG_0001.jpg
│ │ └── IMG_0002.jpg
│ └── March/
│ └── DSC_0099.jpg
├── 2023/
│ └── December/
└── Unsorted/ ← photos with no date at all
Optional: Year/Month/Day/ subfolders, and a RAW/ subfolder per date for RAW files.
- Insert your SD card - PhotoMover detects it automatically and shows it as a source option. You can also browse to any folder manually.
- Pick a destination - choose the folder where organized photos should land. Both paths are saved for next time.
- Load Photos - scans the source and streams thumbnails into the review grid.
- Tag your shots:
- Click a photo to open the full-screen preview; press T to tag for transfer, D for deletion
- Shift-click or drag to multi-select, then tag the whole selection at once
- Use Tag all in the action bar to mark everything
- Transfer - hit the Transfer button; a progress bar tracks the operation file by file. Each file is verified before the original is removed.
- Review the summary - see how many files were transferred, skipped, or errored. Start a new import or go back to review more.
Photos tagged for deletion are moved to Destination/_Rejects/ (with the same copy verification as transfers) - empty that folder yourself once you're sure. Flip the "Keep rejects" toggle off if you want true deletion from the card instead.
| Layer | Technology |
|---|---|
| Shell | Electron 31 |
| UI | React 18 + TypeScript 5 |
| Bundler | electron-vite + Vite 5 |
| Styling | Tailwind CSS 3 |
| State | Zustand |
| EXIF | exifr |
| Thumbnails | Jimp |
| Tests | Vitest |
All dependencies are pure JavaScript - no native build toolchain required.
- Node.js 18 or newer
- npm 9+
git clone git@github.com:alminisl/PhotoMover.git
cd PhotoMover
npm installnpm run devnpm test # unit + workflow-simulation tests
npm run typecheck # strict TypeScript check across main, preload, rendererThe test suite simulates the full SD-card-to-drive workflow against temp directories: thumbnail generation, date organization, collision renaming, duplicate skipping, and verified moves.
npm run package # build for the current platform
npm run package:win # Windows installer (nsis)
npm run package:mac # macOS dmg + zip
npm run package:linux # Linux AppImage + debThe packaged installers land in dist/. Releases are built for all three platforms automatically by GitHub Actions whenever a v* tag is pushed.