Upload files
Give a function bucket access and save uploaded files.
Give a function access to a bucket, then write file bytes under an object key.
Save files from a function
Import your bucket and add it to dependencies.buckets. The name assets makes it available as context.buckets.assets.
This function accepts a primary image and attachments, writes their bytes, and returns their keys:
/** Validates multipart image files, writes them through the declared assets bucket and returns their uploaded names. */
import { defineFunction } from "@relkit/app/functions";
import { z } from "@relkit/app/schema";
import assets from "../buckets/assets.bucket.js";
const uploadedFile = z.file({
maxBytes: 1024 * 1024 * 10,
mediaTypes: ["image/jpeg", "image/png"],
});
const uploadAssets = defineFunction({
input: z.object({
label: z.string().min(1),
primary: uploadedFile,
attachments: z.array(uploadedFile),
}),
output: z.object({
label: z.string(),
files: z.array(z.string()),
}),
dependencies: { buckets: { assets } },
handler: async ({ label, primary, attachments }, context) => {
const files = [primary, ...attachments];
// This demo uses filenames as keys; uploading the same name replaces the file.
await Promise.all(
files.map(async (file) =>
context.buckets.assets.put(file.name, new Uint8Array(await file.arrayBuffer()), {
contentType: file.type,
}),
),
);
return { label, files: files.map(({ name }) => name) };
},
});
export default uploadAssets;
put() takes a key, a Uint8Array, and optional settings such as contentType and metadata. Await it before reporting a successful upload.
Choose keys safely
This example uses filenames as keys. Uploading cover.png again replaces the existing file. In a multi-user app, generate keys on the server—for example, users/<user-id>/<random-id>.png—and save the original display name separately.
Authorize uploads before writing. A declared content type does not prove a file is safe; inspect its contents when your app requires it.
Connect an upload endpoint
Use a route with accept: "multipart/form-data". The image-upload tutorial includes the service, route, and curl request.
The HTTP body limit covers the whole request; file-schema and bucket limits apply to individual files. Keep uploads below all applicable limits. See HTTP uploads for request validation details.