All ten
Photo Trim logo

Photo Trim

iPhone photo library manager with USB backup

Product, native engine, app, backend, landing

Live on the App Store

For people whose photo library outgrew their phone: browse 80,000 photos at 120fps, see at a glance what is on the device versus stranded in iCloud, clear whole months at once, and copy straight to a USB drive without a computer in the middle. Every frame of analysis runs on the phone's neural engine — nothing is uploaded, and the app works with no connection at all.

iOS appCloudflare APIAdmin consoleLanding
174 photos/ssustained analysis, 194 peak
20k–80k+photo libraries handled
120 fpsgrid scrolling
up to 75%saved per Live Photo converted

Screens

Key engineering

thermal-aware background workmulticore enumerationadaptive batchingmemory-pressure handlingcloud asset retrieval + retryincremental discoveryanalysis versioning120fps virtualised gridon-device Neural Engine

Under the hood

Architecture

A native engine with an app around it. Analysis, batching and transfer live in Swift and a pure TypeScript job core; the React Native layer stays presentation. The backend handles accounts and entitlements only — it never sees a photo.

Data & state

Library state is local to the device, keyed by asset. Analysis results carry the version of the algorithm that produced them, so improving detection re-runs only what is stale instead of invalidating the whole library.

Runs on

The phone. The backend is edge functions with a small relational store; the app ships through the store pipelines, with over-the-air updates for everything that is not native code.

Operational risk

The device is the hostile environment — thermal throttling, the lock screen, a pulled cable, and cloud-resident assets that arrive late or not at all. Per-asset failures are tracked rather than averaged away, because a run that silently skipped files is worse than one that failed.

Stack

App
React NativeExpo SDK 57Skiaop-sqliteDrizzleTanStack QuerySentryi18nOTA updates
Native (Swift)
expo-photo-library-toolkitexpo-backup-enginefancy photo gridStoreKit clientPhotoKitNeural Engine
Backend
Cloudflare WorkersHonoD1R2 backup workerBetter Authpasskeyshono-openapiZod
Web
Next.js on OpenNextAstro landingCloudflare Pages
Delivery
Bun workspacesEAS build / submit / updateGitHub Actions matrixversion-bump gates

What it took

  • The analysis engine is the product. A native scanning pipeline that tunes its own batch size and concurrency to the device it is running on, measured at roughly 174 photos per second — fast enough that an 80,000-photo library is a coffee break, not an afternoon.
  • iCloud is the hard part. Photos that live in the cloud behave nothing like photos on the device — they arrive late, or not at all — so the engine treats slow assets as their own problem with retries and per-asset error tracking, rather than guessing and being wrong.
  • Analysis is versioned. Results carry the version of the algorithm that produced them, so improving detection re-runs only what is stale instead of invalidating an entire 80,000-photo library.
  • Triple duplicate detection — exact, near-duplicate and visually similar — plus Live Photo conversion that drops the hidden three-second video and keeps the still.
  • Direct-to-USB transfer from an iPhone, with a resumable job engine underneath: manifest schema, state machine and reporting live in a pure-TypeScript package shared with My Photo Copy.
  • Two apps, one native core. Photo Trim and My Photo Copy ship from one workspace on shared native modules, with release tooling that refuses to publish an unversioned build.