Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.