Defining a Schema
A schema is a description of
- the tables in your Convex project
- the type of documents within your tables
While it is possible to use Convex without defining a schema, adding a
schema.ts
file will give you additional type safety throughout your app.
We recommend beginning your project without a schema for rapid prototyping and then adding a schema once you've solidified your plan. To learn more see our Schema Philosophy.
Schema Enforcement
Currently schemas are a "types only" feature. Adding a schema will give you precise, code generated types, but won't change the runtime behavior of your application.
In the future Convex will support enforcing your schema and rejecting documents that don't match it.
Writing Schemas
Schemas are defined in a schema.ts
file in your convex/
directory and look
like:
import { defineSchema, defineTable, s } from "convex/schema";
export default defineSchema({
channels: defineTable({
name: s.string(),
}),
messages: defineTable({
body: s.string(),
channel: s.id("channels"),
user: s.id("users"),
}),
users: defineTable({
name: s.string(),
tokenIdentifier: s.string(),
}),
});
This schema (which is based on our
Users and Auth tutorial), has 3
tables: channels, messages, and users. Each table is defined using the
defineTable
function. Within each table,
the document type is defined using our schema builder,
s
.
The schema builder supports all of the Convex types. Additionally
you can describe fields that could be one of multiple types using s.union
. If
your table stores multiple different types of documents, you can also use
s.union
at the top level.
Generating a Schema
While writing your schema, it can be helpful to consult the Convex Dashboard. The "Generate Schema" button in the "Data" view suggests a schema declaration based on the data in your tables.
Using Schemas
Once you've defined a schema, rerun npx convex codegen
. This will produce new
versions of dataModel.ts
and
server.ts
.
The Document
type from
dataModel.ts
provides document types for all of
your tables. You can use these both when writing Convex functions and in your
React components:
import { Document } from "../convex/_generated/dataModel";
function MessageView(props: { message: Document<"messages"> }) {
...
}
The query
and
mutation
functions in
server.ts
have the same API as before but now provide
a db
with more precise types. Functions like
db.insert(table, document)
now
understand your schema. Additionally database queries
will now return the correct document type (not any
).