Generate Zod schemas for your SvelteKit models from a field list

Stop hand-writing a Zod schema for every form and endpoint. One vela command turns a field list into a typed schema that drops straight into Superforms, remote functions and server code.

3 min read zodvalidationgeneratorssveltekit

Every SvelteKit form action, remote function and API route needs the same thing before it touches data: a schema that says what a valid request looks like. In a plain SvelteKit project that means opening src/lib/schemas/, writing a z.object() by hand, and keeping it in sync with the database column it validates. The vela generate schema generator does the writing from a one-line description of the model.

Prerequisites

Any SvelteKit project. The generator needs no vela setup, no backend and no component kit, so a fresh one is enough:

$ npx sv create my-app && cd my-app

Run vela with npx vela, or add it to the project with npm install -D vela. If the project has no zod yet, the command installs it alongside the schema.

A project made with npx vela create my-app, or upgraded with npx vela bless, already has Zod and Superforms, which the first example under “Use it” relies on. Coming from vanilla SvelteKit explains what bless adds and what it leaves alone.

Run the command

A schema is a model name followed by fields. Each field is name:type, and a trailing ! makes it required:

$ vela generate schema login email:email! password:text!

What was generated

One file. The model name becomes the file name and the export name:

src/lib/schemas/login.ts
import { z } from "zod";

export const loginSchema = z.object({
  email: z.email(),
  password: z.string().nonempty(),
});

The highlighted lines are the two fields you described. email:email! became z.email(), and password:text! became a non-empty string. Every field type in the generator syntax has a Zod equivalent, so age:number gives you z.number(), role:select(admin:Admin,member:Member) gives you an enum, and a field without ! is wrapped in .optional().

Use it

The schema is plain Zod, so it works anywhere Zod does. In a form action with Superforms:

src/routes/login/+page.server.ts
import { superValidate } from 'sveltekit-superforms';
import { zod4 } from 'sveltekit-superforms/adapters';
import { loginSchema } from '$lib/schemas/login';

export const load = async () => ({ form: await superValidate(zod4(loginSchema)) });

Or on its own, in a +server.ts endpoint:

src/routes/api/login/+server.ts
import { json } from '@sveltejs/kit';
import { loginSchema } from '$lib/schemas/login';

export const POST = async ({ request }) => {
	const body = loginSchema.parse(await request.json());
	return json({ ok: true, email: body.email });
};
Tip
If you also want the form page and the action that uses this schema, run vela generate form instead. It generates the same schema plus the page, the handler and a server test.

Change your mind

Generated files are ordinary source, so you can edit the schema by hand. If you would rather start over, remove it with the matching destroy command:

$ vela destroy schema login

Going further

Related tutorials

Build a validated form in SvelteKit with Zod and Superforms in one command

A SvelteKit form with server-side validation means a schema, a form action, a page wired to Superforms, and a test. vela generate form writes all four from a single field list, so you start from working code instead of boilerplate.

4 min read

SvelteKit remote functions - a validated form without form actions

Remote functions let a SvelteKit form post to a typed server function instead of a form action. vela generate form --remote scaffolds the form, the remote function, the Zod schema and the config flags so you can try the new model in a minute.

3 min read

Define a database collection and schema for SvelteKit from the command line

A new model in a SvelteKit app means a database table, a migration, a Zod schema and TypeScript types that agree with each other. vela generate resource creates all of them from one field list, without opening an admin UI.

3 min read