Migrate a Convex app to Nimbus
Nimbus runs Convex projects in place: it detects the convex/ directory,
runs codegen, and serves the same function and client APIs from a local
binary. Most projects need only a dependency swap and a new deployment URL.
Before you start, scan the compatibility reference for the surfaces your app uses. File storage, search indexes, and crons are not supported today — if your app depends on them, it is not ready to migrate.
What to change
Section titled “What to change”1. Run the dev server from your project root
Section titled “1. Run the dev server from your project root”cd my-convex-appnimbus devnimbus dev detects the convex/ directory, provisions the
Convex-compatible npm package into .nimbus/packages/, runs codegen, and
serves on http://localhost:3210 with an auto-created demo tenant.
2. Swap the convex dependency
Section titled “2. Swap the convex dependency”Point your convex dependency at the package Nimbus provisions, then
reinstall:
{ "dependencies": { "convex": "file:./.nimbus/packages/convex" }}npm installThe regenerated convex/_generated/ files import from convex/server,
convex/browser, and convex/values, and those imports must resolve to the
Nimbus-compatible package rather than the hosted-Convex one.
3. Update the deployment URL
Section titled “3. Update the deployment URL”Nimbus deployment URLs include a tenant segment:
http://localhost:3210/convex/demoSet whatever environment variable your clients read for the Convex
deployment URL (for example VITE_CONVEX_URL or NEXT_PUBLIC_CONVEX_URL)
to that value. You no longer need a CONVEX_DEPLOYMENT value from a hosted
dashboard; nimbus dev records its local deployment in .env.local as
NIMBUS_DEPLOYMENT.
4. Let codegen regenerate _generated/
Section titled “4. Let codegen regenerate _generated/”nimbus dev rewrites convex/_generated/ on every source change. For a
one-shot run without the dev server, use:
nimbus codegen --app .5. Review your auth config
Section titled “5. Review your auth config”convex/auth.config.ts (or .js — exactly one, not both) carries over with
the same provider shapes:
- OIDC:
{ domain, applicationID }. The token’s audience must equalapplicationID, and tokens with multiple audiences are rejected. - Custom JWT:
{ type: "customJwt", issuer, jwks, algorithm }with an optionalapplicationID. The algorithm must beRS256orES256.
process.env reads in the auth config are resolved when codegen runs, so
set those variables in the environment where nimbus dev executes.
What works unchanged
Section titled “What works unchanged”- Function authoring —
query,mutation,action,httpAction, and theirinternalvariants, with the sameargs/handlersyntax. - Schema —
defineSchema,defineTable, indexes, and the core validator set (v.string(),v.number(),v.id(),v.object(),v.union(), and friends). - Database access —
ctx.db.get/insert/patch/deleteand the query builder (withIndex,filter,order,take,collect,first,unique,paginate). - Scheduling —
ctx.scheduler.runAfterandrunAttargeting mutations. - HTTP actions —
httpRouterroutes inconvex/http.ts, served under{deploymentUrl}/http/.... - Node actions —
"use node"modules andconvex.jsonsettings (node.nodeVersion,node.externalPackages). - Clients — the
convex/reacthooks and theconvex/browserHTTP and WebSocket clients, including reactive query subscriptions.
What to check
Section titled “What to check”- File storage —
ctx.storageand the_storagesystem table are not available. - Search — full-text and vector search (
withSearchIndex) are not available. - Crons —
cronJobsfromconvex/serveris not available. db.replace— not available; usectx.db.patchto update fields.- Validators —
v.int64(),v.bytes(),v.record(), andv.float64()are not available; see the compatibility reference for the supported set. usePaginatedQuery— requires functions registered with thepaginatedQueryregistrar (a Nimbus extension exported from./_generated/server). Plainqueryfunctions that call.paginate()still work with direct client calls, but not with the React pagination hook.- System fields — documents carry
_idand_creationTimeas on Convex, plus a Nimbus-specific_updateTime.
Run beyond dev
Section titled “Run beyond dev”nimbus dev is the local loop. To run a standalone server, use
nimbus start — it does not auto-create a tenant, so follow the
self-host quickstart to set one up. For the
broader picture of what compatibility means, see
Coming from Convex.