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.

buckets:
  - name: applications
    default: true
    backend: s3
    config: { bucket: $env.S3_BUCKET, region: us-east-1 }

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.

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.

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.