Zod 3 × Zod 4
svelte-number-format has no Zod dependency at all — bind:value hands you a plain number or raw string, so any
validator (or none) works. Below, the same two bound values are validated live
through both Zod majors at once.
Try an amount over $1,000,000, or clear the field, and watch both columns react.
Zod 3 import { z } from 'zod'
✓ valid
{
"amount": 1500,
"phone": "4155551234"
}Zod 4 import { z } from 'zod/v4'
✓ valid
{
"amount": 1500,
"phone": "4155551234"
}What actually differs
For the schemas these components need, the API is the same in both majors. The differences show up at the edges:
Schemas
// Identical in Zod 3 and Zod 4
import * as z from 'zod' // Zod 3
import * as z from 'zod/v4' // Zod 4 API from the zod@3.25+ package
import * as z from 'zod' // or zod@4 installed directly
const schema = z.object({
amount: z.number().min(0).max(1_000_000),
phone: z.string().regex(/^\d{10}$/, 'Must be exactly 10 digits')
}) Custom error messages
// Custom error params were renamed
z3.number().max(1_000_000, { message: 'Must be ≤ 1,000,000' }) // Zod 3
z4.number().max(1_000_000, { error: 'Must be ≤ 1,000,000' }) // Zod 4
z.number().max(1_000_000, 'Must be ≤ 1,000,000') // both Superforms & Formsnap
// sveltekit-superforms ships an adapter per major
import { zodClient } from 'sveltekit-superforms/adapters' // Zod 3
import { zod4Client } from 'sveltekit-superforms/adapters' // Zod 4 Felte
@felte/validator-zod declares a zod ^3 peer dependency,
so the Felte demo sticks with Zod 3.
SvelteKit remote form functions
// SvelteKit remote form functions accept any Standard
// Schema validator — Zod 3.24+ and Zod 4 both qualify
export const postForm = form(
z.object({ amount: z.number().min(0) }),
async (data) => { /* data.amount is a number */ }
)