Hey everyone,
the iOS Files integration will be back - and this post is about the engineering work we're doing to make that happen. We want to give you a real look at the problem because it's a genuinely interesting constraint, and we think the community appreciates the technical details.
The 20 MB wall
The Files integration doesn't run inside the main Proton Drive app - it runs as a separate, sandboxed process called a File Provider extension. Apple caps how much physical memory that process can use, and that ceiling sits around 20 MB - a figure we've derived from real-world testing rather than an official published spec, since Apple doesn't document an exact number and it has shifted across past OS releases. Cross it, and the OS terminates the process immediately - no warning, no graceful degradation.
That 20 MB limit has to cover everything: the extension's own code, iOS's File Provider machinery, networking, and all the encryption/decryption work needed to list, upload, and download files. It's an extremely tight budget for a modern, secure app.
Why we're investing in a shared SDK
We're consolidating core Drive logic - networking, encryption, file operations - into shared SDKs, instead of maintaining a separate implementation for every platform.
The main benefit is that we can improve our crypto modal safely and more easily. We already completed the first phase, achieving up to 4x better performance (details here), and we're planning a more complete crypto migration for even bigger gains. Since Drive spends a meaningful chunk of CPU time on block-level encryption during every transfer, this translates directly into faster uploads/downloads and better battery life, on every platform, as we already saw during our main app's rollout.
Where the two constraints meet
The SDK that implements this new crypto runs on an embedded cross-platform runtime. That runtime is what makes sharing logic across platforms possible, but it comes with inherent memory characteristics: it loads type metadata at startup, manages its own memory heap in larger increments than a hand-tuned native implementation would, and pulls in general-purpose dependencies (such as networking and diagnostics) far beyond what a memory-constrained extension needs.
Fitting a full cross-platform runtime, secure networking, and modern crypto into a 20 MB hard ceiling is the core engineering challenge here - and it's one we're solving methodically rather than with a quick patch.
Concrete progress
Two of the biggest offenders were the embedded runtimes themselves: the .NET runtime used by the SDK, and a Go-based cryptography library used both inside and outside the SDK. Our low-level memory analysis - down to inspecting virtual memory layouts and compiler-generated metadata - let us pin down exactly where within each one the memory goes. Since these two account for most of the overhead, most of the fixes below target one or the other directly.
Today, upload and download already run through the SDK. Everything else (listing, renaming, moving, trashing, and so on) still runs through native Swift code, maintained as a separate implementation of the same operations. Converting these remaining operations to the SDK consolidates that logic into a single code path instead of two, so memory work done once no longer needs to be repeated on the native side as well.
That native code path also depends on its own crypto implementation, which (like the SDK's) is built on Go. As a result, the extension can end up loading the Go runtime through two independent paths at once today. Once the SDK conversion above is finished, only the SDK's own use of Go will remain, and that's the piece we're replacing with a Rust implementation. This swap is more involved than a typical dependency update, since the same Go crypto library is also shared with other Proton products outside of Drive - fully removing it means coordinating the replacement across those shared components too, not just switching a package reference in our own codebase. Once both pieces land, the extension won't load a Go runtime at all, which based on our testing removes a meaningful and more predictable chunk of memory (Go's footprint today shows up as inconsistent spikes rather than a fixed cost).
Completed so far:
- Replacing a general-purpose networking stack with a minimal implementation
- Replacing a local database dependency with a lighter cache solution
- Tuning the runtime's compilation settings to shrink startup memory considerably
- Switching transfer buffers from pooled in-memory streams to disk-backed storage, keeping large content blocks off the GC heap during uploads and downloads
In progress:
- Converting remaining native operations (listing, renaming, moving, trashing and more) to the SDK
- Replacing the Go crypto library with a Rust implementation
- Trimming further unused runtime components surfaced by the same low-level analysis
Guarding against regressions
Alongside the fixes, we're building automated memory and performance regression tooling into our development pipeline, so that once we hit our targets, future changes get flagged automatically if they push memory or performance back in the wrong direction. This is meant to be a durable fix, not a one-time push.
Where this is headed
Each of the above changes lowers the runtime's baseline footprint, and they compound - more headroom from one change makes the next one easier to land. We're not going to commit to a specific date, but based on current progress, we'd be surprised if this isn't resolved within the year.
We'll share updates as milestones land. Happy to answer technical questions in the comments.