TypebaseTypebase

Troubleshooting

Solutions for the most common issues you might run into with Typebase.

Last updated on

This page covers the issues users hit most often, grouped by the area they show up in. If you don't find your problem here, the underlying libraries are well-documented. Start with oRPC, Drizzle, or better-auth depending on which layer is failing.

Installation

Peer dependency warning about drizzle-orm

When you install Typebase you may see a warning like this:

 WARN  Issues with peer dependencies found
.
└─┬ typebase-io-cli 0.0.1
  ├─┬ @better-auth/drizzle-adapter 1.6.8
  │ └── ✕ unmet peer drizzle-orm@^0.45.2: found 1.0.0-beta.22
  └─┬ better-auth 1.6.8
    └── ✕ unmet peer drizzle-orm@^0.45.2: found 1.0.0-beta.22

Typebase pins drizzle-orm to the 1.0.0-beta line to get the newer query builder, while better-auth and @better-auth/drizzle-adapter still declare ^0.45.2 as their peer range. The APIs Typebase relies on are compatible, so this is safe to ignore. The warning is just the package manager noticing the version mismatch on paper.

Most package managers only warn and continue:

  • npm (v7+): warns, installs everything.
  • yarn classic (v1): warns, installs everything.
  • bun: warns, installs everything.

pnpm is the exception: with strict-peer-dependencies=true (the default in some setups), it will refuse to install. If that happens, add this to the root of your project:

.npmrc
strict-peer-dependencies=false

Then re-run pnpm install.

yarn berry (v2+) installs everything too, but under PnP the missing peer can turn into a runtime resolution error when better-auth tries to import drizzle-orm. The cleanest fix is to widen the peer range via packageExtensions in .yarnrc.yml:

.yarnrc.yml
packageExtensions:
  'better-auth@*':
    peerDependencies:
      drizzle-orm: '*'
  '@better-auth/drizzle-adapter@*':
    peerDependencies:
      drizzle-orm: '*'

Then run yarn install again. Once better-auth bumps its peer range to the Drizzle 1.0 line, none of these workarounds will be needed.

esbuild binary is missing / "you installed esbuild for another platform"

The Typebase CLI uses esbuild to transpile your server before deploying. esbuild ships a native binary and runs a post-install script to place the right one for your platform. Some package managers block post-install scripts by default, so the binary never lands and the CLI errors out the first time you run npx typebase-io-cli deploy or npx typebase-io-cli generate-server.

pnpm (v9+) is the most common case. It prints something like:

╭ Warning ─────────────────────────────────────────────────────────────
│   Ignored build scripts: esbuild.
│   Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
╰──────────────────────────────────────────────────────────────────────

Approve the build once and pnpm will remember it for future installs:

pnpm approve-builds

Pick esbuild from the list. To do it without the prompt, add it to package.json:

package.json
{
  "pnpm": {
    "onlyBuiltDependencies": ["esbuild"]
  }
}

Then re-run pnpm install so the binary downloads.

yarn berry blocks build scripts by default too. Allow esbuild in .yarnrc.yml:

.yarnrc.yml
enableScripts: true

Or, more scoped, use supportedArchitectures / packageExtensions to whitelist esbuild specifically. See the Yarn docs for the narrower options.

bun allows build scripts by default, but if you've locked them down with trustedDependencies, add esbuild:

package.json
{
  "trustedDependencies": ["esbuild"]
}

npm runs post-install scripts by default, so this usually only comes up if you've passed --ignore-scripts.

Codegen

Client types are out of date or missing

The _generated/ folder is a snapshot taken the last time you ran npx typebase-io-cli codegen. Adding, removing, or renaming any of the following requires a fresh run:

  • A file inside actions/
  • auth.ts
  • env.ts
  • publisher.ts
  • db/schema.ts or db/relations.ts
npx typebase-io-cli codegen

You don't need to re-run codegen when you only change the contents of an existing file. The action body, schema columns, or auth options will pick up automatically the next time you build.

"Found auth.ts but no database schema at db/schema.ts"

better-auth stores users, sessions, accounts, and verifications in your database, so auth can't be built without a schema. You'll see this from codegen, generate-server, deploy, and auth generate alike.

Pick whichever you meant:

  • You want auth: create typebase/db/schema.ts (a plain export const per table is enough to start), then run npx typebase-io-cli auth generate to append the auth tables and npx typebase-io-cli db dev push to create them.
  • You don't want auth: delete typebase/auth.ts and run npx typebase-io-cli codegen.

This most often shows up after deleting db/schema.ts from a project that already had auth wired up.

Codegen fails with "cannot find module" or path errors

This usually means projectPath in typebase.json doesn't match where your typebase/ directory actually lives. Check the Configuration page and confirm projectPath is correct relative to your project root.

db is missing from the action context

Two things to check:

  1. You have a typebase/db/schema.ts file. The db client is only injected when one exists.
  2. You ran npx typebase-io-cli codegen after creating it. The action builder is regenerated based on what files exist.

The same applies to auth and publisher. Each requires its matching top-level config file plus a fresh codegen run after that file is created.

"Found publisher.ts but no database schema" or no events table

The db publisher stores its events in your own Postgres database, so typebase/db/schema.ts must export the required events table. The CLI refuses to build without it.

Also add an events: {} entry to typebase/db/relations.ts, following the general rule that every table should be registered for Typebase's relational query API.

init --with-db-publisher scaffolds both definitions. If you added the publisher by hand, copy them from the Publisher page, run npx typebase-io-cli codegen, and push the table with npx typebase-io-cli db dev push before starting the server.

publisher is missing from the action context

Confirm typebase/publisher.ts exists and exports a publisher created with definePublisher, then run npx typebase-io-cli codegen. Adding or removing the file changes the generated action context; editing event definitions inside an existing file does not require codegen.

A key I declared in env.ts isn't on env

env itself appears whenever you have an env.ts, a db/schema.ts, or an auth.ts, but the keys on it come from your defineEnv call. If a key you just added isn't showing up:

  1. Confirm it's inside the object passed to defineEnv, not somewhere else in the file.
  2. If you created env.ts in this session, run npx typebase-io-cli codegen. Adding or removing the file changes the action context; editing the keys inside an existing one doesn't.

See Environment Variables.

Deployment

"Schema changes are destructive" prompt I didn't expect

The CLI flags any change that drops a table, drops a column, or renames a column. If you're seeing this when you didn't intend to lose data, it usually means a schema edit was unintentional. For example, you renamed a column without telling Drizzle (Drizzle sees this as a drop + add). Cancel the prompt, restore the old name, and run npx typebase-io-cli deploy again.

Deploy succeeds but my server can't reach the database

The CLI sets DATABASE_URL on your provider on the first deploy. If you've rotated the Neon connection string or moved branches manually, the value on your provider may be stale. Check the current value with dev or prod depending on the environment that's failing:

npx typebase-io-cli env dev get DATABASE_URL
npx typebase-io-cli env prod get DATABASE_URL

Then replace it with the new one, against the same target:

npx typebase-io-cli env dev add DATABASE_URL <new-value>
npx typebase-io-cli env prod add DATABASE_URL <new-value>

If env get prints ENCRYPTED, the provider is hiding the raw secret. In that case, check or replace the value from the original source instead, usually your provider dashboard or Neon project settings.

The server exits at boot with "invalid environment variables"

The deployed server validates your env schema before it serves anything, and prints exactly which keys failed:

✗ Typebase server failed to start.

  Invalid environment variables:
    RESEND_API_KEY  Required

  Set them with:
    npx typebase-io-cli env prod add <KEY> <value>

Set the missing key against the target that's failing, then redeploy:

npx typebase-io-cli env prod add RESEND_API_KEY <value>

DATABASE_URL and BETTER_AUTH_SECRET are synced by deploy itself, so seeing one of those in the list usually means the provider value was removed or rotated by hand.

generate-server or deploy fails with "no defineEnv call was found"

Your typebase/env.ts exists but the CLI can't find a defineEnv(...) call to read the schema from. It reads the file statically, so the call has to be visible in the source: defineEnv({ ... }) with an inline object, or with a local variable that holds one. A schema built by a function call (defineEnv(getSchema())) can't be resolved, and reports "defineEnv must be called with an inline object literal" instead.

If you don't need any variables of your own, keep the empty call that init scaffolds (defineEnv({})) or delete env.ts entirely and rerun codegen.

generate-server or deploy cannot read publisher.ts

The CLI reads the publisher config statically so it can generate the server around the selected provider. Keep a visible definePublisher(...) call in publisher.ts, pass it an object the CLI can resolve, write provider as a plain string such as 'db', and include an events property. The simplest supported shape is the one on the Publisher page.

Deploy fails partway through

npx typebase-io-cli deploy runs several steps in sequence. If it fails between steps, the partial state is usually safe to retry. The CLI is idempotent for the early steps (codegen, generate-server, transpile) and the destructive ones (schema push, deploy) are gated on the previous step succeeding. Re-run the same command.

If it keeps failing on the same step, run that step in isolation to see the underlying error:

  • Schema push errors → npx typebase-io-cli db dev push
  • Auth/secret errors → npx typebase-io-cli env dev get BETTER_AUTH_SECRET (some providers return ENCRYPTED instead of the raw value)
  • Provider errors → log into your provider's dashboard and check the deployment log

Provider authentication expired

Vercel, Cloudflare, and Deno all use short-lived tokens. If you suddenly get 401s during deploy, log in again. The CLI will prompt you. There's no separate "logout" step; just re-run npx typebase-io-cli deploy and authenticate when asked.

Deno Deploy returns "502 Server Error"

When deploying to Deno Deploy you may occasionally see an HTML response like this:

<html>
  <head>
    <title>502 Server Error</title>
  </head>
  <body>
    <h1>Error: Server Error</h1>
    <h2>
      The server encountered a temporary error and could not complete your request.
      <p>Please try again in 30 seconds.</p>
    </h2>
  </body>
</html>

This is returned by Deno Deploy's API gateway, typically when you've hit a rate limit on their side. Wait ~30 seconds and re-run the command. Most of the time the next attempt goes through.

If you're hitting this repeatedly and it's blocking your workflow, the simplest fix is to switch to another provider. Typebase also supports Vercel and Cloudflare Workers. Point your typebase.json at one of them and re-deploy.

Cloudflare Workers: "Worker exceeded CPU time limit."

When calling a deployed route on Cloudflare Workers you may see a response like:

{
  "message": "Worker exceeded CPU time limit.",
  "outcome": "exceededCpu",
  "statusCode": 503
}

Cloudflare enforces a hard CPU-time budget per request, separate from wall-clock time. The Workers Free plan caps requests at 10ms of CPU time, and the Paid plan at 30s. The error is returned when your handler burns more CPU than the cap, regardless of how fast the I/O around it was.

You'll find the actual CPU time used per request in the Cloudflare dashboard under Workers & Pages → your worker → Observability → Logs, or via npx wrangler tail <worker-name>.

The three usual fixes, in order of how aggressive you want to be:

1. Upgrade your Workers plan

The Free plan's 10ms limit is genuinely impractical for anything CPU-heavy. The Paid plan ($5/month at the time of writing) raises the limit to 30s, which fits any normal workload. If you're shipping a real app on Cloudflare, this is the expected baseline.

2. Check if your action is doing CPU-intensive work

If you're on the Paid plan and still hitting the limit, your handler is doing something expensive on the hot path. Common culprits:

  • Large JSON parses or stringifies
  • Big in-memory loops over collections
  • Synchronous compression/encryption
  • Heavy template or markdown rendering

Move the expensive part off the request path (queue + Durable Object + scheduled job) or do it on the client.

3. Replace the auth password hasher with Node's scrypt

The most common cause of this error is password hashing during sign-up / sign-in. better-auth's default scrypt implementation is pure JavaScript, which burns a lot of CPU time on Workers. Node's built-in node:crypto.scryptSync is implemented in native code via OpenSSL and runs orders of magnitude faster, fast enough to fit comfortably under the Workers Paid limit (and sometimes even under the Free limit).

Cloudflare Workers expose node:crypto via the Node.js compatibility flag, which Typebase enables by default for Cloudflare deployments.

Override the hasher in your auth.ts:

typebase/auth.ts
import { defineAuth } from 'typebase-io/server';
import { scryptSync, randomBytes, timingSafeEqual } from 'node:crypto';

export const auth = defineAuth({
  // ...
  emailAndPassword: {
    enabled: true,
    password: {
      async hash(password: string) {
        const salt = randomBytes(16).toString('hex');
        const derivedKey = scryptSync(password, salt, 64);
        return `${salt}:${derivedKey.toString('hex')}`;
      },
      async verify({ hash, password }) {
        const [salt, key] = hash.split(':');
        const derivedKey = scryptSync(password, salt, 64);
        return timingSafeEqual(Buffer.from(key, 'hex'), derivedKey);
      },
    },
  },
});

Note that swapping the hasher means existing users hashed with the old implementation won't be able to log in until they reset their password, so do this before you have real users.

Database

"Relation does not exist" when querying

You added a table to schema.ts but haven't pushed the schema to the database branch you're querying. Push to the target that's failing. dev is the common case, but the same issue happens on prod if you deploy code that references a table you never pushed there:

npx typebase-io-cli db dev push
npx typebase-io-cli db prod push

Or just deploy: npx typebase-io-cli deploy dev / npx typebase-io-cli deploy prod runs the push automatically for each target.

"No relations found" when using db.query.X

Every table exported from schema.ts must also appear in db/relations.ts, even if it has no foreign keys. See Relations for the empty-entry pattern.

Schema push hangs or times out

Neon free-tier branches sleep when idle and take a few seconds to wake up. The first push after a long gap can be slow. If it hangs for more than ~30 seconds, cancel and retry. The second attempt will hit the awake branch.

Auth

auth generate says "no schema file found"

You need both typebase/auth.ts and typebase/db/schema.ts before running auth generate. The command appends auth tables to your existing schema; it won't create one from scratch.

Sessions don't persist on the frontend

The most common cause is a missing or misconfigured proxy. Auth cookies must be set on your frontend's domain, not on your Typebase server's domain. See the proxy setup section in your framework's integration guide (Next.js, SvelteKit, Nuxt).

If you're using Expo, sessions are stored in SecureStore instead of cookies. Make sure the expoClient plugin is wired up on the client and the expo() plugin is in your auth.ts.

"Origin not trusted" errors

Add the exact origin to trustedOrigins in your auth.ts:

trustedOrigins: ['http://localhost:3000', 'https://my-app.vercel.app'];

For Expo dev builds you'll also need scheme entries like myapp:// and exp://**. See the Expo guide for the full list.

Local development

generate-server output is stale

The generated server in typebase/_server/ is a snapshot of the moment you ran the command. Re-run npx typebase-io-cli generate-server and restart the local server after changing anything inside typebase/.

To stop doing that by hand, run npx typebase-io-cli generate-server --watch: it rebuilds on every change and stops on x or Ctrl+C. The rebuilt files still need the server process restarted to take effect. If you find yourself in this loop constantly, deploying to dev is usually smoother. See Work locally.

Local server starts but my frontend can't reach it

Three things to check:

  1. TYPEBASE_APP_URL in your frontend's .env points to http://localhost:8080 (or whichever port your local server uses).
  2. If you have an auth.ts, your frontend's local origin is in trustedOrigins.
  3. Your local server actually has a working DATABASE_URL and BETTER_AUTH_SECRET in typebase/_server/.env, along with every key you declared in env.ts. A server missing any of them exits at startup with a list of what's wrong rather than serving requests. Note that the generated server reads a plain DATABASE_URL, while the CLI writes two separate values into your project-root .env (DATABASE_URL for the prod branch and DATABASE_URL_DEV for the dev branch) so they can coexist. Copy whichever branch you want to run against into typebase/_server/.env as DATABASE_URL. If the value is missing from your project root, fetch it from the provider with npx typebase-io-cli env dev get DATABASE_URL or npx typebase-io-cli env prod get DATABASE_URL. If that returns ENCRYPTED, grab the value from the Neon console instead.

Still stuck?

If none of the above helps, please open an issue on GitHub with:

  • What you ran
  • The full error output
  • Your typebase.json (with secrets redacted)
  • Your framework and Node version

We'll triage and either fix the underlying issue or add it to this page.

On this page