Most issues when working with RefactKit fall into a small set of categories: database connectivity, authentication configuration, environment variable mistakes, and version coupling between framework packages. The sections below walk through each known issue with its root cause and the steps to resolve it.Documentation Index
Fetch the complete documentation index at: https://docs.refactkit.com/llms.txt
Use this file to discover all available pages before exploring further.
pnpm dev.prepare: false is required for Supabase Pooler — connection fails on port 5432
prepare: false is required for Supabase Pooler — connection fails on port 5432
prepared statement ... already exists or the connection hangs indefinitely.Root cause: Supabase’s Transaction Pooler (port 6543) does not support PostgreSQL prepared statements. If you use the direct connection string (port 5432) or forget to set prepare: false in the postgres.js client, the driver tries to use prepared statements and the connection fails.Solution: Use port 6543 in your DATABASE_URL and ensure prepare: false is set in db/index.ts:drizzle-kit push during local development), use port 5432 only for that command and keep port 6543 for the runtime DATABASE_URL.Database schema out of sync — queries fail after adding or changing a table
Database schema out of sync — queries fail after adding or changing a table
column "x" does not exist or relation "y" does not exist after you edit db/schema.ts.Root cause: Drizzle ORM’s schema file is the source of truth, but changes to it are not automatically applied to your database. You must explicitly push the schema.Solution: Run the following command every time you change db/schema.ts:ALTER TABLE or CREATE TABLE statements. No migration files are created — changes are applied directly.Rotating BETTER_AUTH_SECRET invalidates all active sessions
Rotating BETTER_AUTH_SECRET invalidates all active sessions
BETTER_AUTH_SECRET is used to sign and encrypt session tokens. Changing this value makes all existing tokens unverifiable, which signs out every active user immediately.Solution: Plan secret rotations carefully. Announce scheduled maintenance if your application has active users. To rotate:- Generate a new secret:
openssl rand -base64 32 - Update
BETTER_AUTH_SECRETin your deployment environment - Redeploy — all existing sessions will be invalidated on the next request
SUPABASE_SERVICE_ROLE_KEY exposed client-side — bypasses Row Level Security
SUPABASE_SERVICE_ROLE_KEY exposed client-side — bypasses Row Level Security
SUPABASE_SERVICE_ROLE_KEY with VITE_ and it is now visible in the browser’s network tab or bundled JavaScript.Root cause: Vite exposes any environment variable prefixed with VITE_ to the client bundle. The SUPABASE_SERVICE_ROLE_KEY bypasses Supabase Row Level Security entirely — if it reaches the browser, anyone can read or write any row in your database.Solution: Remove the VITE_ prefix immediately. This variable must only ever be used in server-side code:TanStack Start + Nitro version mismatch — SSR server crashes on startup
TanStack Start + Nitro version mismatch — SSR server crashes on startup
pnpm dev or a production build crashes with errors like Cannot find module or unexpected SSR behavior after updating packages.Root cause: TanStack Start and Nitro v3 are tightly coupled. The nitro package is pinned to 3.0.x-beta in package.json. Upgrading @tanstack/react-start or @tanstack/react-router without a matching Nitro version — or vice versa — breaks the SSR layer.Solution: Do not run pnpm update across all packages. Update these packages individually and verify the build and tests pass after each change:Better Auth update adds new database columns — app crashes after upgrade
Better Auth update adds new database columns — app crashes after upgrade
pnpm update better-auth, server functions start throwing database errors about missing columns.Root cause: Better Auth’s organization plugin and other plugins add columns to the user, session, member, and organization tables as the library evolves. Updating the package without pushing the updated schema leaves the database out of sync.Solution: After every Better Auth update, check the changelog and push the schema:Emails going to spam in production — domain not verified in Resend
Emails going to spam in production — domain not verified in Resend
- Go to Resend Dashboard → Domains → Add Domain
- Enter your sending domain (e.g.,
yourdomain.com) - Add the provided SPF and DKIM DNS records to your DNS provider
- Wait for Resend to confirm verification (usually under 5 minutes)
- Update
EMAIL_FROMin your environment to use the verified domain:
@gmail.com, @yahoo.com, or other shared domains as a sender — use a domain you control.React 19 compatibility — third-party UI library fails to install or render
React 19 compatibility — third-party UI library fails to install or render
react@^18 as a required peer dependency. Check the library’s changelog for a React 19 compatibility release before adding it. If you need a component that is not in shadcn/ui, build it using Base UI primitives, which are already included and fully compatible:SSR hydration mismatch — React warning about server/client content difference
SSR hydration mismatch — React warning about server/client content difference
Hydration failed because the server rendered HTML didn't match the client. Parts of the UI may flash or reset on load.Root cause: SSR renders the page on the server and sends HTML to the browser. React then “hydrates” that HTML by attaching event handlers. If the data or markup produced on the server differs from what React produces on the client, hydration fails. Common causes include reading browser-only globals (window, localStorage), using Math.random() or Date.now() directly in render, or having query cache data that differs between server and client.Solution: Use ensureQueryData in route loaders to pre-populate the TanStack Query cache during SSR, so the client uses identical data:useEffect or use the useIsClient pattern:Locale not persisting — language resets to default on page refresh
Locale not persisting — language resets to default on page refresh
setLocale() works immediately, but the selected locale resets to English after a page reload or navigation.Root cause: Locale state is held in React context. Without a cookie to persist the selection across requests, the server always falls back to the default locale during SSR and sends the wrong lang attribute in the HTML before the client can correct it.Solution: The locale must be stored in a cookie so the server can read it during SSR. RefactKit’s i18n system reads the lk_locale cookie via getServerLocale() in the root loader. Verify the cookie is being written when setLocale is called:getServerLocale() reads the lk_locale cookie name and that the call happens in the root layout’s loader before SSR renders.