natedunn
natedunn2w ago

Standard schema

With Zod 3 going in maintenance mode and Zod utils in convex-helpers seemingly only supporting v3, I was wondering if this was the moment we could consider supporting the Standard Schema natively for validation and schemas? This would allow us to use traditional v values in Convex, but also allow us to use Arktype, Zod, Valibot, etc. Thoughts?
GitHub
GitHub - standard-schema/standard-schema: A standard interface for ...
A standard interface for TypeScript schema validation libraries - standard-schema/standard-schema
26 Replies
Convex Bot
Convex Bot2w ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
natedunn
natedunnOP2w ago
Want to bump this in case it was missed.
ian
ian2w ago
Are you willing to play with an alpha of a helper and give feedback if I make one?
natedunn
natedunnOP2w ago
oh definitely ping me and I'll jump right in
ian
ian2w ago
Try out convex-helpers@0.1.88-alpha.0 import { toStandardSchema } from "convex-helpers/standardSchema";
natedunn
natedunnOP2w ago
on it
ian
ian2w ago
GitHub
Add standard schema support by ianmacartney · Pull Request #593 ·...
not quite #558 but at least you can do something like import { toStandardSchema } from &amp;quot;convex-helpers/standardSchema&amp;quot;; const standardValidator = toStandardSchema(v.object({ na...
natedunn
natedunnOP2w ago
ah so instead of supporting natively (or with helper, which is fine) it converts convex v to standard schema acceptable format? that makes sense. good quality of life if that is the design intent I'll test that further
ian
ian2w ago
yup exactly until we build that in, this is the easiest route and building that in means owning using core validators for runtime validation, whereas I'm doing that via another helper I've written. currently convex validators are executed in Rust, so only on args/returns, and schema validation
natedunn
natedunnOP2w ago
I still think it would be nice to have fromStandardSchema along with toStandardSchema if that makes sense
ian
ian2w ago
ah - I don't think that'd work. I don't think there's a runtime value for the kind of validation happening - only type-time I have helpers to convert from zod to convex, but that requires digging deep into zod's internals to figure out what it's trying to validate, to replace with the equivalent convex one
natedunn
natedunnOP2w ago
ahhh well that would make it more complicated.
ian
ian2w ago
But accepting any standard schema as arg validators / returns validators / schema validators would be cool. the problem with that is the Rust thing again. By storing it in the Convex validator format, we can guarantee that all of your data at rest matches your schema validator, even if you do something like changing from a string to a specific literal (if all your strings are that literal)
natedunn
natedunnOP2w ago
yeah i was originally thinking something like this if using a helper
export default defineSchema({
tasks: defineTable(fromValidator(
type({
text: type("string"),
isCompleted: type("boolean"),
})
))
profiles: defineTable(fromValidator(
z.object({
name: z.string(),
description: z.string().optional(),
})
))
});
export default defineSchema({
tasks: defineTable(fromValidator(
type({
text: type("string"),
isCompleted: type("boolean"),
})
))
profiles: defineTable(fromValidator(
z.object({
name: z.string(),
description: z.string().optional(),
})
))
});
ian
ian2w ago
using JS runtime validation would require scanning the whole table and running it on it, whenever the validator changes and also running it on any/all streaming imports (which currently go from fivetran straight to the DB, using the rust validation) You can currently do defineTable(zodToConvex(zodSchema)) but that's specific to zod lmk if the library is good enough to ship, and if so I can cut a new helpers release
natedunn
natedunnOP2w ago
yeah im using zodToConvex rn. works great with v3 but I thought the jump to v4 would be a good opptunity to rethink that. but I think you are right that its only type-time for standard schema at the end of the day the needs are the same: get tigher control of validation while not needing to double up writing those validations, and using different APIs so its nice to be able to plug the v validators into something that is standard schema compat, but you ideally need to be committed to just using that as a validator. i'll plug any other issues I see on the PR though
ian
ian2w ago
Yeah I'm thinking for zod v4 to publish @convex-dev/zod that is similar but only does zod v4, since the implementation will need to change, and I've been meaning to split more things into separate packages anyways
natedunn
natedunnOP2w ago
or maybe thinking about how drizzle does validator refinements. scaffold the structure of the schema and then refine it after. basic type checking there can happen without disrupting the Rust thing
natedunn
natedunnOP2w ago
Drizzle ORM - drizzle-zod
Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.
ian
ian2w ago
ah, so extend convexToZod to allow refinements - cool
natedunn
natedunnOP2w ago
yeah just an idea to avoid conflicts
ian
ian2w ago
take your schema, then make more refined zod validators I like that as it doesn't mislead people about what the guarantee the DB is providing
natedunn
natedunnOP2w ago
exactly technically in drizzle-zod or drizzle-fill-in-the-blank you can either extend or override
const userSelectSchema = createSelectSchema(users, {
name: (schema) => schema.max(20),
bio: () => z.string().max(100).nullable(),
});
const userSelectSchema = createSelectSchema(users, {
name: (schema) => schema.max(20),
bio: () => z.string().max(100).nullable(),
});
ian
ian2w ago
If you want to take a crack at it, put up a PR. Or file an issue so we don't forget. I'm going back to agent stuff now - just released an Agent playground today
natedunn
natedunnOP2w ago
ayyy look at that
ian
ian2w ago
For everyone else - this is live now! import { toStandardSchema } from "convex-helpers/standardSchema";

Did you find this page helpful?