The action prop on <form>
The simplest form pattern: pass a Server Action to the form's action prop. Submission triggers the action with the form's FormData. The page re-renders with whatever revalidatePath invalidated.
Reading FormData
FormData entries are strings (or files). Use formData.get('name') as string for typed access. For files, type-narrow with formData.get('avatar') as File.
Passing extra arguments with .bind()
You often want to pass an id or context that's not in the form. Use .bind(null, id) — the bound argument arrives before the FormData. The framework safely encrypts the bound value before sending the action reference to the client.
Treat every FormData entry and every bound value as untrusted. Narrow strings and files through a schema, validate upload size and type, and recheck ownership for a bound resource ID. Encryption protects transport details; it does not establish permission. Form field names are part of the server action input contract, so a UI-only rename can silently drop a value. Compare FormData keys before and after submission in tests. A hidden input and .bind() differ in interface intent, not in authority. Bind values the user should not edit, but never rely on their obscurity. The action must remain safe when called directly. Submit text, a file, and a bound ID with JavaScript enabled and disabled. Tamper with the identifier, exceed the file limit, and omit fields. The server should reject each case without writing or leaving temporary upload data behind.