Convex 0.19.0 has been released! This release includes changes foreshadowed in our last release and constitutes our first 1.0 release candidate.

The main updates in 0.19.0 are:

  • Objects keys in the database and in function input/output can be most strings
  • Support for Maps and Sets was removed
  • v.bigint has been removed in favor of v.int64
  • ConvexProviderWithClerk takes useAuth prop
  • Class Id was removed

Arbitrary Object keys

Prior to this release, the keys of all Objects passed as arguments, returned from functions, or written to the database had to be in the valid identifier format. The identifier format allows only alphanumeric characters and _, has maximum length of 64 characters, and cannot begin with a number.

In this release, we are lifting some of these constraints — keys in objects at runtime must be in the valid field name format. The field name format allows any non-control ASCII characters, has maximum length of 1024 characters and cannot begin with $ (to avoid ambiguity with our serialization protocol).

For example foo-bar is a valid field name, but not a valid identifier (it contains -), and foo_bar is both a valid field name and valid identifier.

Fields referenced in schemas, argument validators, or db.query expressions must still be valid identifiers, but otherwise keys in objects only need to be valid field names, which gives more flexibility for returning and storing objects. For example a function can return a mapping from document IDs to metadata or store JSON from a third party within a document.

Disallowed Maps and Sets

Check out our previous release notes for the context on our deprecation of Maps and Sets.

Starting with this release you can no longer send these types as arguments to functions (queries/mutations/actions) or return them from functions.

You can still read them from the database in your functions, but you cannot write them.

The corresponding validators and v.set have been removed.

Below is an example migration process for migrating existing data. For more on migrations in general see this stack article.

  1. If you’re using a schema, change your existing v.set()  and validator uses to v.any()
  2. Write an internalMutation which migrates your data from the deprecated Map and Set types to their alternative
import { internalMutation } from "../_generated/server";

export const migrate = internalMutation(async ({ db }) => {
  const allDocs = await db.query("myTable").collect();
  for (const doc of allDocs) {
    // Migrate Sets in `myField` to Arrays
    await db.patch(doc._id, { myField: [...doc.myField] });
    // Migrate Maps with string keys in `myField` to Objects
    await db.patch(doc._id, { myField: Object.fromEntries(doc.myField) });
    // Migrate Maps with different keys in `myField` to Arrays of Objects
    await db.patch(doc._id, {
      myField: [...doc.myField].map(([key, value]) => ({ key, value })),
  1. Run the mutation(s) with npx convex run
  2. After all your data was migrated you can replace the uses of v.any() from step 1 with:
    • From the original v.set(myType) to v.array(myType)
    • From the original, valueType) to:
      • v.any() if using Objects
      • v.array(v.object({key: keyType, value: valueType})) if using Arrays of Objects

We plan to expand our type system in the near future to include a v.record() validator for typing Objects similarly to Maps with a key and value type. Please reach out if migrating off of Maps will pose a challenge to your project.

ConvexProviderWithClerk takes useAuth prop

To avoid React Context issues ConvexProviderWithClerk no longer uses Clerk’s useAuth hook directly, instead the hook must be passed into the provider as a prop:

// newly import `useAuth` from @clerk/clerk-...
import { ClerkProvider, useAuth } from "@clerk/clerk-react";
import { ConvexProviderWithClerk } from "convex/react-clerk";

      { /* newly pass `useAuth` to the `useAuth` prop */ }
      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
        <App />

Removing v.bigint

In this version the v.bigint validator has been removed entirely. Use v.int64 instead. See previous release notes for more details.

Removing the class Id

The Id class has been removed in favor of string IDs and the Id type (which maps to strings at runtime). See the release notes for 0.17.0 for more details.