Skip to content

Commit 807b080

Browse files
sethconvexclaude
andcommitted
Add batch upload APIs for truly parallel file uploads
The old upload flow spawned 2 `npx convex run` subprocesses per file (generateUploadUrl + recordAsset), each taking ~2-3s startup overhead. For 16 files that's 32 subprocess calls, effectively serial despite the concurrency pool. New flow uses batch functions: 1. One `generateUploadUrls` call → N URLs (1 subprocess) 2. Upload all files via fetch in parallel (0 subprocesses) 3. One `recordAssets` call → record all (1 subprocess) Total: 3 subprocess calls instead of 2N+1. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 22499f2 commit 807b080

10 files changed

Lines changed: 329 additions & 175 deletions

File tree

dist/cli/upload.js

Lines changed: 106 additions & 72 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/cli/upload.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/client/index.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ export declare function exposeUploadApi(component: ComponentApi): {
6161
deleted: number;
6262
blobIds: string[];
6363
}>>;
64+
/**
65+
* Generate multiple signed upload URLs in one call.
66+
* Much faster than calling generateUploadUrl N times.
67+
*/
68+
generateUploadUrls: import("convex/server").RegisteredMutation<"internal", {
69+
count: number;
70+
}, Promise<string[]>>;
71+
/**
72+
* Record multiple uploaded assets in one call.
73+
*/
74+
recordAssets: import("convex/server").RegisteredMutation<"internal", {
75+
assets: {
76+
path: string;
77+
contentType: string;
78+
deploymentId: string;
79+
storageId: string;
80+
}[];
81+
}, Promise<void>>;
6482
/**
6583
* List all static assets (for debugging).
6684
*/

dist/client/index.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/client/index.js

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/client/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/component/schema.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
1111
blobId: import("convex/values").VString<string | undefined, "optional">;
1212
contentType: import("convex/values").VString<string, "required">;
1313
deploymentId: import("convex/values").VString<string, "required">;
14-
}, "required", "blobId" | "path" | "contentType" | "deploymentId" | "storageId">, {
14+
}, "required", "path" | "blobId" | "contentType" | "deploymentId" | "storageId">, {
1515
by_path: ["path", "_creationTime"];
1616
by_deploymentId: ["deploymentId", "_creationTime"];
1717
}, {}, {}>;

example/convex/staticHosting.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66

77
// Expose the upload API as INTERNAL functions.
88
// These can only be called via `npx convex run` - not from the public internet.
9-
export const { generateUploadUrl, recordAsset, gcOldAssets, listAssets } =
9+
export const { generateUploadUrl, generateUploadUrls, recordAsset, recordAssets, gcOldAssets, listAssets } =
1010
exposeUploadApi(components.selfHosting);
1111

1212
// Expose the deployment query for live reload notifications.

0 commit comments

Comments
 (0)