Convex 0.17.0 is out and we have a few big changes to improve developer ergonomics!
- Breaking: Convex document IDs are now strings, not classes.
- Breaking: References to functions use
api
objects (useQuery(api.messages.list)
notuseQuery("messages:list")
) and support jump-to-definition in your editor!
and also:
- Breaking:
convex/schema
has been merged intoconvex/server
to avoid naming conflicts with imports. ConvexReactClient
now includes aquery
method for performing a one-shot non-reactive query.
These changes are backwards compatible and your current clients will continue to work with Convex, but upgrading to 0.17.0 will require some code changes to please read on for more info.
If you encounter any challenges migrating to 0.17.0 please reach out to us in the Convex Discord Community or at support@convex.dev.
Breaking: Document IDs are strings
As of version 0.17.0, Document IDs are now strings instead of instances of the Id
class. String IDs can now be compared directly with ===
and are much easier to pass to other services or across JSON-serialized boundaries.
JS | .toString() | |
---|---|---|
Old IDs (class) | new Id("users", "LZ_YyWnYaZSFKTnOpihMPA") | "LZ_YyWnYaZSFKTnOpihMPA" |
New IDs (string) | “30pszp69d7c6k54554wwx9h89gycxhr” | "30pszp69d7c6k54554wwx9h89gycxhr" |
Existing clients that still use the Id
class will continue to work and existing server functions on 0.16 or earlier will continue to receive the Id
class from database calls.
Id<"tableName">
is still the correct way to type IDs since it enables TypeScript to differentiate between ID strings and other strings at compile time.
Client changes
doc._id.equals(otherDoc._id)
should be replaced withdoc._id === otherDoc._id
.doc._id.id
should be replaced withdoc._id
.new Id(...)
is no longer supported and in general all IDs should come from reading and writing documents from Convex. If a dummy ID is needed for an optimistic update it can be created based on a random string, e.g.,_id: crypto.randomUUID() as Id<"tableName">
.
Server changes
- Methods on
db
accept the new ID format and do not need to be updated. - The function
db.normalizeId(tableName, idString)
can be used to convert an ID in either format to the new format if needed, e.g.:
db.normalizeId("users", "30pszp69d7c6k54554wwx9h89gycxhr")
// "30pszp69d7c6k54554wwx9h89gycxhr"
db.normalizeId("users", "LZ_YyWnYaZSFKTnOpihMPA")
// Converts to new format: "30pszp69d7c6k54554wwx9h89gycxhr"
db.normalizeId("messages", "30pszp69d7c6k54554wwx9h89gycxhr")
// Returns null since ID does not belong to table "messages"
Breaking: Refer to Convex functions with an api
object
Convex functions are now referred to from JavaScript/TypeScript clients with an api
object instead of strings.
useQuery(api.messages.list) // instead of the old useQuery("messages:list")
API objects have a variety of advantages over strings: less boilerplate code generation, simpler TypeScript types, and our favorite… jump to definition for Convex functions! (cmd-click/ctrl-click in VS Code)
Applications using Convex 0.17.0 or later will need to be updated to use the new syntax.
Manual migration
- Import
useQuery
,usePaginatedQuery
,useMutation
,useAction
, anduseQueries
from"convex/react"
. - Import the
api
object from"./convex/_generated/api"
and remove old imports of theAPI
type. - Update
useQuery()
and friends (runMutation
,scheduler.runAt
, etc) from using the string function name"folder/module:function"
toapi.folder.module.function
, e.g.,useQuery("messages:list")
→useQuery(api.messages.list)
. - Import
cronJobs
from"convex/server"
if needed.
If your application isn’t using codegen (this is rare) you can convert a string function name via the makeFunctionReference
method, e.g., useQuery(makeFunctionReference<"query">("messages:list"))
.
Automatic migration
Large applications may benefit from this codemod that should automatically update your code to the new syntax. This conversion is best-effort so you should review these changes after it runs.
Breaking: convex/schema
merged into convex/server
defineTable
and defineSchema
are now exported from convex/server
not convex/schema
. This fixed ambiguous imports from convex/schema
in products with ./convex/schema.ts
and a project-level baseUrl
.
One-shot queries
The typical way to execute a query in Convex is the useQuery
hook which subscribes to updates on the results of the query. For convenience we’ve also added a query
method to ConvexReactClient
which performs a one-shot non-reactive query.