Convex ctx.db API Update: Explicit Table Names and the Future of Custom IDs
Convex `ctx.db` APIs now require explicit table names for `get`, `patch`, `replace`, and `delete`. This change improves security, consistency, and paves the way for custom IDs. Migrate your codebase with automated tools.
The article introduces an important update to the ctx.db APIs in Convex, starting with version 1.31.0. Key functions such as db.get, db.patch, db.replace, and db.delete now require the table name as their first argument. This change enhances safety, improves consistency, and lays the groundwork for future features like custom IDs. While existing code remains functional, automatic migration tools are available to help developers update their projects.
What's Changing in the ctx.db API?
Effective with convex NPM package version 1.31.0, the db.get, db.patch, db.replace, and db.delete methods now mandate the table name as the initial argument.

Old API (Table Inferred from 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 API (Table Name Explicitly Provided):
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);
Why This Change? Paving the Way for Custom IDs
This API modification serves several strategic purposes:
- Improved Ergonomics and Symmetry: The update standardizes the
ctx.dbAPIs, making them more consistent and intuitive to use across the board. - Support for Bring Your Own ID (BYO-ID): A highly requested feature, BYO-ID allows developers to provide their own IDs for documents. This is particularly useful for data migration from other databases or for optimistic ID generation on client-side applications that support offline functionality. To safely implement BYO-ID, the
ctx.dbAPI must explicitly know the target table name, as Convex's current special_idformat (which implicitly encodes the table) will no longer be the sole method for identification. - Enhanced Security: The new APIs offer greater security, especially in scenarios where
v.string()is used for validation instead ofv.id("tablename"). Previously, assuming a string was anId<"someTable">while an attacker passed anId<"someOtherTable">could lead to vulnerabilities. Explicitly providing the table name mitigates such risks. Developers are always advised to usev.idwith argument validators to ensure robust ID validation.
Convex's existing document _id field has a special format that encodes the table it belongs to, without exposing the table name directly. This allows v.id("tablename") to guarantee that an ID is valid only for its intended table, enabling safe calls to db.get(id) with validated IDs. However, with custom IDs, v.id cannot infer the table, making it essential for the ctx.db APIs to receive the table name explicitly.
Will This Impact Existing Projects?
No, your current code will continue to function after updating to convex 1.31.0. The older APIs are still supported, so immediate migration isn't necessary. However, the old APIs will be deprecated in the future.
In rare instances, primarily for advanced users with custom implementations of GenericDatabaseReader or GenericDatabaseWriter, the update to 1.31.0 might cause type checking errors. Such users will need to adjust their implementations to align with the new method signatures.
How to Update Your Existing Codebase
Convex provides automated tools to facilitate this migration:
1. Using ESLint (Recommended)
The most effective way to update is by leveraging the Convex ESLint plugin. This plugin not only assists with API migration but also helps enforce Convex best practices.
A new rule, @convex-dev/explicit-table-ids, has been added. It automatically infers table names from TypeScript types and inserts them into your code.
If you're already using the plugin, update @convex-dev/eslint-plugin to version 1.1.0 or later. Then, run the following command to automatically update your code:
npx eslint . --fix
2. Without ESLint
For environments where ESLint cannot be used, a standalone tool, @convex-dev/codemod, is available for automatic code migration. Execute it with:
npx @convex-dev/codemod@latest explicit-ids
Limitations of Migration Tools
Both migration tools rely on TypeScript types to accurately update your codebase. If your types are not sufficiently precise to determine the correct table name, the tools will issue a warning, requiring you to manually add the table name.

Specifically, if your code utilizes unions of multiple ID types, you may need to refactor it to clarify the types.

Should you encounter unexpected issues with the migration tools, please consider opening an issue on GitHub.
For Users of convex-helpers and convex-test
If your project uses convex-test, or the Triggers or Row-level security features from convex-helpers, you'll need to update these dependencies to utilize the new APIs:
convex-test: Update to version 0.0.39 or later.Triggers(fromconvex-helpers): Updateconvex-helpersto version 0.1.106 or later.Row-level security(fromconvex-helpers): Updateconvex-helpersto version 0.1.107 or later.
Conclusion
The ctx.db APIs are transitioning to a (tableName, id, ...) signature. This change promotes API consistency, enhances security, and paves the way for advanced features like custom IDs. Developers can efficiently update their codebases using the Convex ESLint plugin or the standalone codemod tool.