Resumable Cloud Storage uploads from Bubble: a recovery design for large files

The short answer
Use a resumable upload when restarting a large file from byte zero would create unacceptable delay or waste. A trusted service should authorize the Bubble user and create a session for one predetermined object. The browser can then transfer the file, query the persisted offset after an interruption, and continue from that point. After Cloud Storage reports completion, a server-side process still needs to verify the object and update the Bubble file record.
Resumability solves interrupted byte transfer. It does not solve tenant authorization, file-type policy, malware handling, duplicate requests, or application status. The session URI is itself a bearer credential and must not be logged, stored in analytics, or shared beyond the client that needs it.
This design goes deeper than choosing direct versus server-mediated upload. It focuses on what must happen after the connection drops, the tab reloads, or the client is unsure how many bytes Cloud Storage accepted.
When resumability is worth the complexity
Google recommends resumable uploads for large files or slow connections because an interrupted transfer can continue rather than restart. The benefit grows with file size, network instability, and the cost of asking a user to repeat work. It may be less useful for small files that finish quickly, where a single-request upload and a simple retry are easier to operate.
Choose the threshold from observed behavior. Consider median and upper-percentile file sizes, mobile networks, user geography, browser memory, retry frequency, and support cost. Avoid publishing a universal size cutoff unless it comes from a tested client and current provider guidance.
A resumable design adds state that someone must own:
a Bubble-side upload record;
an opaque destination object name;
a Cloud Storage session URI held by the browser;
expected file size and safe metadata;
persisted byte offset;
session creation and expiry times;
completion and verification states;
retry and replacement rules.
If the team cannot reconcile those states, resumability can create more confusing failures than it prevents.
Separate the application record from the session
Create an upload record before the bytes move. Give it a stable application ID and bind it to the authenticated user, tenant, intended file purpose, expected size range, and an opaque object identifier chosen by the trusted service. The browser should request work using the application ID, not supply an arbitrary bucket path.
The session URI belongs to the transfer layer. Google's resumable upload documentation states that the URI acts as an authentication token: anyone who has it can upload to the target object without further authentication. Keep it in short-lived client storage only when necessary, send it over HTTPS, and remove it when the upload completes, is cancelled, or must restart.
Do not persist the session URI in a normal Bubble data field. That can expose it through page data, debugging tools, privacy-rule mistakes, exports, or logs. Persist safe state instead: upload ID, object ID, status, confirmed byte count, expected size, timestamps, and a sanitized error classification.
Initiate the session in a trusted service
A common browser-direct sequence is:
Bubble sends an authenticated create-upload request.
The service derives the actor and tenant from trusted authentication.
It checks policy for file purpose, expected size, content type, and account limits.
It reserves a unique object name and creates or loads an idempotent upload record.
It initiates a Cloud Storage resumable session for that object.
It returns the session URI only to the authorized browser.
The browser transfers one or more byte ranges.
On completion, the service verifies the object before changing status to available.
The initial request should carry an idempotency key so a double click or network retry does not reserve multiple objects. The service can return the same active application upload when the same actor repeats the same bounded request. If policy requires a new session after expiry, create it under a controlled transition and retain the old session's sanitized history.
For a cross-origin browser, include the browser's Origin header when the server initiates the session. Google notes that Cloud Storage uses that initial origin to determine CORS headers for later requests. See Cloud Storage CORS for Bubble for the broader origin and preflight review.
Transfer chunks without inventing progress
The browser can send the entire file in one request through the resumable session or divide it into chunks. Chunking makes pause, retry, and progress behavior more explicit, but requires careful offset handling. Do not advance the application status solely because the browser attempted a chunk.
Track three different values:
selected bytes: the size of the local file the user chose;
sent bytes: what the browser attempted to transmit;
persisted bytes: what Cloud Storage confirms it has retained.
Only persisted bytes are a durable recovery point. If a request times out, the browser may not know whether Cloud Storage accepted all, some, or none of the range. Query the session status, read the confirmed range, and continue from the next required offset. Do not blindly replay new data at a guessed position.
Google documents that already persisted bytes cannot be overwritten within a resumable session and that attempts to resend earlier ranges are ignored until the service reaches the first unpersisted byte. The client should nevertheless send the same source bytes when retrying. If the local file changed after the session began, cancel the attempt and start a new governed upload instead of combining content from two versions.
Design for the uncertain response
The hardest case is not a clean error. It is an uncertain outcome: the browser sent a final chunk, the connection broke, and no completion response arrived. Treat that as reconciling, not failed and not available.
A recovery routine can:
query the session to determine the persisted offset or completion state;
compare the result with expected size;
resume from the confirmed offset when the session is active;
request a new authorized session when the old one is invalid;
verify the final object independently;
update the application record once.
Cloud Storage documents that resumable sessions must complete within one week and can be cancelled earlier. A client that receives 410 Gone or 404 Not Found for an invalid session should not loop indefinitely. Return to the trusted service, reauthorize the current user, and decide whether to restart from byte zero under a new session.
Integrity and completion are separate
A completed transfer should not immediately become a customer-visible file. Verify at least:
the object exists at the expected bucket and opaque name;
size matches the policy and application record;
generation or version matches the completion being reconciled;
content type is plausible but not blindly trusted;
an integrity value is checked when the chosen client supports it;
tenant and file-purpose metadata match trusted records;
any required scanning or transformation has finished;
the old object is not silently overwritten unless replacement was approved.
Google recommends final-object integrity checks, especially for large files transferred over long periods. It also notes that intermediate chunks do not receive the same whole-object integrity check. The application should retain a verifying state until the final object has passed the checks relevant to its use.
A Bubble status model users can understand
The UI does not need to expose transport jargon. A useful mapping is:
Internal state | User-facing message | Safe action |
|---|---|---|
| Ready to upload | Start |
| Uploading | Pause or cancel if supported |
| Connection interrupted | Resume |
| Checking uploaded progress | Wait |
| Checking file | Wait |
| Ready | Open |
| File could not be accepted | Replace or contact support |
| Upload session expired | Start again |
Show progress from confirmed transfer data when possible. Avoid displaying 100% as “done” while server-side verification is pending. The existing guide How to show upload status and recover from failed uploads in Bubble covers the broader application state pattern.
Negative tests that matter
Run these with synthetic files and two synthetic tenants:
tenant B cannot request or resume tenant A's upload;
a repeated initiation request returns one logical upload;
a lost response after a middle chunk resumes from the confirmed offset;
a lost response after the final chunk enters reconciliation;
an expired or cancelled session triggers reauthorization, not an infinite retry;
a modified local file cannot continue an old session;
an oversized file is rejected before expensive transfer when possible;
a successful transfer with failed verification never becomes available;
session URIs are absent from logs, analytics, error reports, and Bubble fields;
cancellation cannot delete or alter another tenant's object.
Also test page refresh and browser restart if the product promises recovery across either event. If the session URI is intentionally not persisted, be honest that recovery may be limited to the current page lifetime.
Operational ownership
The browser owns selection, byte transfer, and local progress. The trusted service owns authorization, object naming, policy, idempotency, and final verification. Cloud Storage owns the resumable session and persisted object. Bubble owns the customer-visible record and status, but it should learn readiness from verified server state rather than from a page event alone.
Log correlation IDs, application upload IDs, tenant-safe internal identifiers, transitions, byte counts, and sanitized error classes. Do not log the session URI, signed request, raw file content, or customer filename unless there is a documented need and retention policy.
The design decision
Resumable upload is a good fit when large or interruption-prone transfers justify a stateful recovery protocol. It is not automatically the right default for every Bubble file. Start with a clear threshold, one idempotent application record, one trusted initiation service, a browser client that can query offsets, and a verification step that decides when the file is truly ready.
For the surrounding choices, read Bubble direct vs server-mediated uploads, Cloud Storage CORS for Bubble, and the Bubble file-upload security checklist.
Primary keyword: Bubble resumable Cloud Storage upload
Primary CTA: Describe the largest file and weakest network your Bubble workflow must handle.
Sources checked: Cloud Storage resumable uploads, Cloud Storage signed URLs, Cloud Storage CORS, and Bubble file uploads, checked 2026-10-02.
