TL;DR Starting from convex 1.31.0, the db.get, db.patch, db.replace, and db.delete functions take the table name as the first argument. The new API is safer and allows for more customization in the future. Existing code will still work, and you can migrate your existing code automatically.
What is being changed?
In version 1.31.0 of the convex NPM package, we changed db.get, db.patch, db.replace, and db.delete to take the table name as the first argument:
// ❌ Old APIs: without a table name (the table is inferred from the ID)
await ctx.db.get(id);
await ctx.db.patch(id, { message: "New message" });
await ctx.db.replace(id, {
author: "Nicolas",
message: "New message",
});
await ctx.db.delete(id);
// ✅ New APIs: with a table name
await ctx.db.get("messages", id);
await ctx.db.patch("messages", id, { message: "New message" });
await ctx.db.replace("messages", id, {
author: "Nicolas",
message: "New message",
});
await ctx.db.delete("messages", id);Paving the way for BYO-ID
Why are we changing these APIs?
First, this update improves ergonomics and makes all the ctx.db APIs symmetric.
Second, providing your own IDs for documents has been a longstanding request, and one we’ve wanted to support for years. This is useful when migrating data from other databases or optimistically generating IDs on clients, for apps that work offline. In order to support this safely, the ctx.db API needs to clearly specify the table name.[1]
Third, the new APIs are also more secure in cases where you are using v.string() instead of v.id("tablename") for validation (and using type casts instead).[2]
Before we can support custom IDs, we need to stop relying on our special current ID encoding. If you haven’t noticed, the Convex document
_idfield is not your typical UUID. It is a special format that currently encodes the table it belongs to (without leaking the table name). This allows argument validation withv.id("tablename")that guarantees the ID will only work for that table, and allows you to calldb.get(id)safely with a validated ID. However, if a custom ID is provided,v.idwill not be able to know what table the ID is intended for, so it’s necessary for thectx.dbAPIs to know the table name you’re working on. ↩︎These vulnerabilities occur when your code assumes a string is an
Id<"someTable">, while an attacker passes anId<"someOtherTable">. As a rule, always use argument validators withv.idto validate IDs. ↩︎
Will this break my existing projects?
No, your existing code will still work after updating to convex 1.31.0. The old APIs are still supported for now, so you don’t need to migrate immediately. In the future, we’ll deprecate the old APIs.
In rare cases, the update to 1.31.0 might cause type checking to fail. This is the case for advanced users who have custom implementations of GenericDatabaseReader/GenericDatabaseWriter in their codebase: if that’s the case, you’ll need to update your implementation to support the new method signatures.
How do I update my existing codebase?
You can update your code automatically! We built tools that automatically add the missing argument.
With ESLint (recommended)
The best way to update is by using the Convex ESLint plugin. This plugin also helps you follow Convex best practices, so we highly recommend setting it up in your codebase.
We added a new rule, @convex-dev/explicit-table-ids, that automatically infers the table name from the TypeScript types, and adds it for you.
To install the ESLint plugin, follow the instructions at docs.convex.dev/eslint. If you’re already using it, update @convex-dev/eslint-plugin to version 1.1.0 (or later). You can then automatically update your code with:
npx eslint . --fix
Without ESLint
If you can’t use ESLint, we made a standalone tool (@convex-dev/codemod) that also performs the code migration automatically. Run it using:
npx @convex-dev/codemod@latest explicit-idsLimitations
Both tools use TypeScript types to determine how to update your code automatically. If your types aren’t precise enough to determine the table name, the tools will emit a warning, and you’ll need to manually add the right table name.

In particular, if your code uses unions of multiple ID types, you might need to reorganize it to disambiguate the types.

If you’re getting other unexpected issues with the migration tools, please open an issue on GitHub.
For users of convex-helpers and convex-test
If you’re using convex-test, or the Triggers or Row-level security features from convex-helpers, you’ll need to update these dependencies so that you can use the new APIs:
- convex-test: update to version 0.0.39 or later
- Triggers: update convex-helpers to version 0.1.106 or later
- Row-level security: update convex-helpers to version 0.1.107 or later
Summary
We are changing the ctx.db APIs to take (tableName, id, …). This makes the new API more consistent, safer, and prepares for future support of custom IDs. You can update your codebase automatically with ESLint or the standalone codemod tool.