Skip to content
Sarj Code Standards

no-server-file-uploads

Keep native File handling outside explicit server boundaries.

Why

Accepting uploaded files routes their bytes through application workers, consuming connections, memory or temporary disk. Direct signed-URL uploads keep that transfer in object storage.

Fix

Issue an authorized, short-lived signed URL; upload the browser File directly to storage, then submit its object key and metadata. Use Blob for server-generated binary content.

Examples

Before — flagged Accept an object key instead of file bytes
app/actions.ts
"use server";
export async function upload(file: File) {
return file.name;
}
After — preferred Send the browser File directly to storage
app/upload.ts
"use client";
export async function upload(file: File, signedUrl: string) {
await fetch(signedUrl, {
method: "PUT",
body: file,
signal: AbortSignal.timeout(60000),
});
}
Before — flagged Do not receive a file through a Hono route
src/server.ts
import { Hono } from "hono";
const app = new Hono();
app.post("/upload", async (c) => {
const body = await c.req.parseBody();
return c.json({ uploaded: body.file instanceof File });
});
After — preferred Finalize a previously authorized upload
app/actions.ts
"use server";
export async function complete(objectKey: string) {
return validateUploadedObject(objectKey);
}

References