Migrate a Convex app to Nimbus
Nimbus runs Convex projects in place: it detects the convex/ directory,
swaps the convex dependency to its own provisioned package, runs codegen,
and serves the same function and client APIs from a local binary. Most
projects need only nimbus dev 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”# in your existing Convex app directorynimbus 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. Let it swap the convex dependency
Section titled “2. Let it swap the convex dependency”There is no manual dependency edit. When nimbus dev provisions, it also
rewires the convex entry in your package.json from the registry spec to
the provisioned copy and reinstalls dependencies:
{ "dependencies": { "convex": "file:./.nimbus/packages/convex" }}The 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 — which the
rewired dependency guarantees.
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.
Nimbus binds each generated auth configuration to one deployment silo. The URL silo selects that trusted verifier before Nimbus examines a bearer; there is no global subject- or issuer-to-silo lookup. When deploying outside the dev loop, name the silo explicitly:
nimbus deploy [TARGET] --convex-silo demoNIMBUS_CONVEX_SILO is the environment-variable equivalent. A Convex deploy
without either value is refused before activation.
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"action modules run on Nimbus’s Node-compatible runtime (node-compat on V8, not a separate Node process). See the two Convex runtimes for how the default and Node runtimes differ. - Clients — the
convex/reacthooks and theconvex/browserHTTP and WebSocket clients, including reactive query subscriptions.
What to check
Section titled “What to check”convex.json— read and honored.node.nodeVersionselects the Node lane for your"use node"actions ("20","22","24", or"26"; default"24"),node.externalPackagesis enforced at codegen — an undeclared npm import in a"use node"module is a hard error — andfunctionsrelocates the source directory. SettinggenerateCommonJSApiemits a CommonJSconvex/_generated/api_cjs.cjsalongside the ES module one.- 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.