createServerFn
Creates a type-safe server function that can be called from the client with automatic serialization and middleware support.
Basic Usage
import { createServerFn } from '@tanstack/react-start'
const getUserFn = createServerFn({ method: 'GET' }).handler(async () => {
// This code only runs on the server
return { name: 'John Doe', email: '[email protected]' }
})
// Call from client
const user = await getUserFn()
API Reference
method
'GET' | 'POST'
default:"'GET'"
The HTTP method to use for the server function. GET requests serialize data in the URL query string, while POST requests send data in the request body.
Builder Methods
The createServerFn() function returns a builder with chainable methods:
.middleware()
Adds middleware to the server function for request/response processing.
middlewares
Array<Middleware>
required
Array of middleware functions or middleware instances to apply to this server function.
const authMiddleware = createMiddleware().server(async ({ next }) => {
// Check authentication
return next({ context: { userId: '123' } })
})
const protectedFn = createServerFn()
.middleware([authMiddleware])
.handler(async ({ context }) => {
console.log(context.userId) // '123'
return { success: true }
})
Validates and transforms input data using a validator (Zod, Valibot, ArkType, or custom function).
A validation schema or function that validates the input data. Supports Standard Schema validators like Zod, Valibot, and ArkType.
import { z } from 'zod'
const createUserFn = createServerFn({ method: 'POST' })
.inputValidator(z.object({
name: z.string(),
email: z.string().email(),
}))
.handler(async ({ data }) => {
// data is typed as { name: string, email: string }
return { id: '1', ...data }
})
// Call with validated data
await createUserFn({ data: { name: 'Jane', email: '[email protected]' } })
.handler()
Defines the server-side handler function that executes when the server function is called.
The server-side function to execute. Receives a context object with data, context, method, and serverFnMeta.
const myFn = createServerFn().handler(async (ctx) => {
// ctx.data - Input data (after validation)
// ctx.context - Context from middleware
// ctx.method - HTTP method ('GET' | 'POST')
// ctx.serverFnMeta - Metadata (id, name, filename)
return { result: 'success' }
})
Handler Context
The handler function receives a context object with the following properties:
The validated input data. Type is inferred from the inputValidator if provided.
Context object accumulated from middleware. Contains values added by middleware and global context.
The HTTP method used for this server function.
Metadata about the server function including:
id: Unique function identifier
name: Function name
filename: Source file path
Calling Server Functions
Server functions can be called with optional configuration:
// No input data
await myFn()
// With input data
await myFn({ data: { name: 'John' } })
// With headers
await myFn({
data: { name: 'John' },
headers: { 'X-Custom': 'value' }
})
// With custom fetch
await myFn({
data: { name: 'John' },
fetch: customFetch
})
// With abort signal
const controller = new AbortController()
await myFn({
data: { name: 'John' },
signal: controller.signal
})
Call Options
The input data to send to the server. Required if inputValidator requires input.
Custom headers to include in the request.
AbortSignal for cancelling the request.
Custom fetch implementation to use instead of global fetch.
Method Selection
GET Requests
- Data is serialized in URL query parameters
- Suitable for idempotent operations
- Limited payload size
- Cacheable by browsers and CDNs
const fetchUserFn = createServerFn({ method: 'GET' })
.inputValidator((userId: string) => userId)
.handler(async ({ data }) => {
return await db.user.findById(data)
})
POST Requests
- Data sent in request body
- Supports larger payloads
- Supports FormData for file uploads
- Not cached by default
const uploadFileFn = createServerFn({ method: 'POST' })
.handler(async ({ data }) => {
if (data instanceof FormData) {
const file = data.get('file')
// Handle file upload
}
return { success: true }
})
Advanced Examples
Chaining Multiple Middleware
const complexFn = createServerFn()
.middleware([authMiddleware, loggingMiddleware])
.inputValidator(mySchema)
.handler(async ({ data, context }) => {
// Access context from all middleware
return { result: data }
})
Returning Responses
const customResponseFn = createServerFn().handler(async () => {
// Return a custom Response object
return new Response('Custom content', {
headers: { 'Content-Type': 'text/plain' }
})
})
Error Handling
const errorFn = createServerFn().handler(async () => {
throw new Error('Something went wrong')
// Error is automatically serialized and thrown on client
})
try {
await errorFn()
} catch (error) {
console.error(error.message) // 'Something went wrong'
}
Type Safety
Server functions are fully type-safe:
- Input types are inferred from validators
- Context types are inferred from middleware
- Return types are preserved across the network
- Serialization is automatically validated
const typedFn = createServerFn({ method: 'POST' })
.inputValidator(z.object({ count: z.number() }))
.handler(async ({ data }) => {
// data is typed as { count: number }
return { doubled: data.count * 2 }
})
// result is typed as { doubled: number }
const result = await typedFn({ data: { count: 5 } })