Execution contract
- Use when
- Use for app-internal, type-safe calls to databases, secrets, or other server-only capabilities.
- Avoid when
- Use a Server Route instead for external systems, webhooks, or cross-origin clients.
- Preconditions
- Choose GET or POST, define a runtime validator, and isolate implementation details in a server-only file.
- Verification
- Test valid and invalid input, confirm client output excludes secrets and database code, and verify the result is serializable.
- Failure mode
- TypeScript does not validate network input; malformed data reaching the handler indicates a missing or incorrect validator.
- Security
- Authenticate and authorize inside every handler; route visibility is not a server authorization boundary.
Use when
Code needs database, secret environment, or filesystem access and is called only by the current Start app. Use a Server Route for a public external API.
Minimal implementation
The default method is GET. Use POST explicitly for operations with write side effects.
import { createServerFn } from '@tanstack/react-start'
export const getServerTime = createServerFn().handler(async () => {
return { now: new Date().toISOString() }
})
export const createIssue = createServerFn({ method: 'POST' }).handler(
async () => ({ ok: true }),
)
Security boundary
A Server Function is same-origin RPC. Start installs its CSRF middleware automatically when there is no custom src/start.ts; once that file is customized, add createCsrfMiddleware explicitly. CSRF protection does not replace authentication, authorization, or input validation, and a typed caller does not make a request trusted.