Skip to main content
View as Markdown

Form File Uploads

Forms can collect files — resumes, invoices, photos, documents — and persist them to your own storage instead of a third-party CDN. Attachment fields render a file picker (and optional drag-and-drop zone), validate type and size before upload, show progress and previews, and submit a canonical { url, name, size, mimeType } metadata object. Files land in a configured app.buckets[] destination on your S3, local disk, or database storage.

app.yaml
buckets:
  - name: applications
    maxFileSize: 10485760

forms:
  - id: 1
    name: apply
    title: Job Application
    path: /apply
    submitTo: { table: applications }
    fields:
      - { kind: standalone, name: full_name, inputType: single-line-text, required: true }
      - kind: standalone
        name: resume
        inputType: attachment
        label: Resume
        required: true
        accept: 'application/pdf,.doc,.docx'
        maxFileSize: 10485760 # 10 MB
        dropZone: true

Attachment Field Configuration

Attachment behavior is configured the same way on both field kinds: a kind: standalone field with inputType: attachment, or a kind: table-field whose underlying column is single-attachment / multiple-attachments. The upload props are shared.

Property Description
accept Comma-separated MIME types or extensions restricting the file dialog (e.g. image/*, application/pdf, .doc,.docx).
maxFileSize Maximum size in bytes per file. Larger files are rejected with an inline error before upload starts.
maxFiles Maximum number of files (multiple-file fields only). Selecting more surfaces an inline error.
dropZone Render a drag-and-drop area alongside the picker, accepting the same files.

Bucket Binding

The storage destination comes from app.buckets[]. A form inherits a default bucket: the bucket whose default: true flag is set, or the only bucket when exactly one is defined. Files are uploaded there on submit, and the form payload carries canonical metadata for each file. Per-field bucket overrides are reserved for a follow-up release.

app.yaml
buckets:
  - name: documents
    default: true
    backend: local
    config: { path: ./storage/documents }

forms:
  - id: 2
    name: invoice-upload
    title: Upload Invoice
    submitTo: { automation: process-invoice }
    fields:
      - { kind: standalone, name: vendor, inputType: single-line-text, required: true }
      - kind: standalone
        name: document
        inputType: attachment
        accept: 'application/pdf,image/*'
        maxFileSize: 20971520 # 20 MB
        dropZone: true

Upload UX

The attachment field renders a complete upload experience:

Behavior Description
Type filter accept restricts both the browser dialog and drag-and-drop; mismatched files surface an inline error.
Size validation maxFileSize rejects oversized files before upload begins.
Progress indicator A progress bar or spinner is shown while each file uploads.
Preview Image files render a thumbnail after upload; non-image files render filename + size.
Remove Selected files can be removed before submit (keyboard-accessible); removing one of many does not affect the others.
Required enforcement A required attachment field with no file blocks submission with an inline error.

File Metadata Shape

When the form submits, each attachment value is normalized to a canonical metadata object — the same shape consumed by submitTo.table, submitTo.automation triggers, and the form_submissions ledger data payload.

app.ts
type FileMetadata = {
  url: string // canonical URL into the bucket (signed when the bucket is private)
  name: string // original filename
  size: number // bytes
  mimeType: string // detected MIME type
}

A single-file field submits FileMetadata | null; a multiple-file field submits FileMetadata[]. Routing the upload to an automation makes the same metadata available in the trigger payload — for example to run an AI extraction over {{trigger.data.document.url}}.

  • Form Fields — the field kinds attachment uploads extend.
  • Forms OverviewsubmitTo targets that receive file metadata.
  • Submissions — file metadata stored in the ledger data payload.
  • Buckets — configuring S3, local, and database storage backends.

Last updated August 11, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.

Built with Sovrium