#How to use Zod to define my Convex Schema
14 messages · Page 1 of 1 (latest)
Hi @safe linden. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
You can use Zod to define your Convex schema by leveraging the zodOutputToConvex function from the convex-helpers package. This allows you to write your data models in Zod and convert them into Convex validators for use in your schema and function argument validation.
1. Defining Your Schema with Zod and zodOutputToConvex
First, define your data model using Zod:
import { z } from "zod";
export const zUser = z.object({
name: z.string(),
email: z.string().email(),
age: z.number().optional(),
});
Then, use zodOutputToConvex to convert your Zod schema to a Convex validator and define your table:
import { defineSchema, defineTable } from "convex/server";
import { zodOutputToConvex } from "convex-helpers/server/zod";
export default defineSchema({
users: defineTable(zodOutputToConvex(zUser)),
});
This approach allows you to keep your data model in Zod and avoid duplicating type definitions for Convex.
2. Validating Input and Output
-
Input Validation:
You can use Zod validators directly in your function arguments by using helpers likezCustomQueryorwithZod. This ensures that incoming data matches your Zod schema before any logic runs.import { z } from "zod"; import { zCustomQuery } from "convex-helpers/server/zod"; import { query } from "./_generated/server"; import { NoOp } from "convex-helpers/server/customFunctions"; const zQuery = zCustomQuery(query, NoOp); export const getUser = zQuery({ args: { id: z.string() }, handler: async (ctx, args) => { // Your logic here }, });This will validate the arguments using Zod before the handler runs.
- Output Validation:
You can also validate outputs using Zod, typically by running your Zod schema on the data before returning it from your function. Some helpers support anoutputorreturnsproperty for this purpose, but the exact syntax may depend on the helper version you use. See the discussion here.
3. Edge Cases and Caveats
-
Schema Enforcement:
If your Zod schema is more refined than what Convex supports (e.g.,z.string().email()), Convex will only enforce the base type (string), not the refinement (email format). So, while your Zod validation will catch invalid emails at runtime, Convex's schema enforcement at rest will not. This means data inserted via the dashboard or CLI may bypass your Zod refinements and only be checked for base types. -
Transforms and Defaults:
If your Zod schema uses transforms, defaults, or effects, be aware thatzodOutputToConvexwill only validate the output type. For example, if you have a default value or a transform, the Convex validator will match the output after those are applied. If you want to validate input before transforms, usezodToConvexinstead. This distinction is important for ensuring your data matches expectations both before and after Zod processing. -
Data Consistency:
If you change your Zod schema, you may need to run migrations to ensure existing data matches the new schema. Otherwise, you risk runtime errors when reading or writing data that doesn't conform to the updated schema.
- Manual Validation on Writes:
For stricter guarantees, consider validating data with Zod before writing to the database, especially if you rely on refinements or transforms that Convex's base validators can't enforce at rest. You can wrap your database writes in a function that runs Zod validation first.
For more details and examples, see the Stack Convex post on Zod and Convex.
Summary:
- Define your schema in Zod.
- Use
zodOutputToConvex(zodSchema)withdefineTablein your Convex schema. - Use Zod for input validation in your functions.
- Be aware of the limitations around refinements, transforms, and schema enforcement at rest.
- Consider manual validation and migrations for stricter data consistency.
If you need more advanced examples or run into specific issues, the convex-helpers repo and the Convex Discord are good resources for up-to-date patterns and support.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@safe linden Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@lone sphinx when self-hosting convex, running convex env list returns No environment variables set., even though I have a .env file located next to my docker-compose.yml. I know I can set variables with the CLI, but it seems like it's not respecting my .env file.
Let me check the knowledge base for you again. One moment! :books:
When self-hosting Convex, the .env file you place next to your docker-compose.yml is used by Docker to set environment variables for the backend and dashboard containers. However, these environment variables are not automatically visible to the Convex CLI commands like convex env list.
The Convex CLI manages environment variables at the deployment level (i.e., stored in the backend's database), not by reading from your local .env file. This means:
- The
.envfile is used by Docker to configure the running backend, but the CLI'sconvex env listcommand only shows variables that have been explicitly set in the deployment via the CLI or the dashboard, not those in your.envfile. - If you want environment variables to appear in
convex env list, you must set them using the CLI (npx convex env set ...) or through the dashboard, even when self-hosting.
This behavior is by design and is consistent with how Convex separates deployment configuration from local environment files. The CLI does not read your .env file for environment variables to display or manage in the deployment context; it only interacts with variables stored in the backend's environment variable store.
For reference, see the self-hosting documentation and the Discord discussion on environment variables, which clarify that .env.local (or .env) is used for deployment info by the CLI, but not for deployment environment variables themselves.
Summary:
Your .env file configures Docker containers, but Convex CLI environment variable commands only interact with variables set via the CLI or dashboard, not those in .env. This is expected behavior when self-hosting Convex.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@safe linden Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@lone sphinx if I set the variables through the dashboard or the CLI, will they remain as long as I don't delete the docker volume?
Let me check the knowledge base for you again. One moment! :books:
Yes, if you set environment variables through the dashboard or the CLI, they are stored in the backend's database. As long as you do not delete the Docker volume that persists the database, these environment variables will remain intact across restarts and upgrades. The self-hosted Convex backend stores its state, including environment variables, in the database managed by Docker. If the volume is deleted, you will lose the stored data, including environment variables, and would need to re-set them after recreating the volume and database Get-convex self-hosted README.