drizzle-team / drizzle-team/drizzle-orm
[BUG]: drizzle-kit silently prefers a stale transitive `@libsql/client` over `@tursodatabase/serverless`, failing `turso://` URLs with `URL_SCHEME_NOT_SUPPORTED`
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Report hasn't been filed before.
- [x] I have verified that the bug I'm about to report hasn't been filed before.
### What version of `drizzle-orm` are you using?
1.0.0-rc.4
### What version of `drizzle-kit` are you using?
1.0.0-rc.4
### Other packages
@tursodatabase/serverless@1.4.0
### Describe the Bug
**What is the undesired behavior?**
With `dialect: "turso"`, drizzle-kit picks its database driver by probing for installed packages, and it probes `@libsql/client` **before** `@tursodatabase/serverless` (`connectToTursoRemote` in `bin.cjs`):
```js
connectToTursoRemote = async (credentials) => {
if (await checkPackage("@libsql/client")) {
const { createClient } = await import("@libsql/client");
...
```
`checkPackage` answers `true` for *any* resolvable package — including a transitive leftover the project does not directly depend on. In our pnpm monorepo we had migrated the app from `@libsql/client` to the new `@tursodatabase/serverless` SDK, but the lockfile still contained a stale peer resolution (`drizzle-orm` lists `@libsql/client` as an optional peer), so the old client remained in `node_modules`.
As a result, `drizzle-kit migrate` loaded `@libsql/client` — which does not accept the `turso://` scheme that the Turso Cloud dashboard now hands out — and failed in CI with:
```
LibsqlError: URL_SCHEME_NOT_SUPPORTED
```
Meanwhile the application itself connected fine with the exact same URL, because at runtime it uses `@tursodatabase/serverless` (1.4+ normalizes `turso://` → `https://` internally). Debugging this was quite confusing because the turso-remote code path (unlike the local-sqlite path) prints no `Using '...' driver for database querying` info line, so nothing indicated that drizzle-kit had picked a different driver than the app uses.
**What are the steps to reproduce it?**
1. `pnpm add drizzle-orm@1.0.0-rc.4 drizzle-kit@1.0.0-rc.4 @tursodatabase/serverless`
2. Make `@libsql/client` resolvable without being a direct dependency (in our case: a stale lockfile peer-resolution from before the SDK migration; `pnpm add @libsql/client` also reproduces the driver-precedence behavior)
3. `drizzle.config.ts`:
```ts
export default defineConfig({
dialect: "turso",
schema: "./schema.ts",
dbCredentials: {
url: "turso://.turso.io", // as issued by the Turso Cloud dashboard
authToken: "",
},
});
```
4. `npx drizzle-kit push` (or `migrate`) → `LibsqlError: URL_SCHEME_NOT_SUPPORTED`
5. Remove `@libsql/client` from the dependency tree (reinstall `drizzle-orm` so the lockfile drops the stale resolution) → drizzle-kit falls back to `@tursodatabase/serverless` and the same URL works (modulo a separate issue with the bundled copy of that SDK, which I'm filing separately — it will appear as a cross-reference on this issue)
**What is the desired result?**
Any of these would have avoided the failure:
- For `dialect: "turso"`, prefer `@tursodatabase/serverless` / `@tursodatabase/database` (the current-generation SDKs) over `@libsql/client` when both are resolvable — or prefer whichever the project *directly* depends on
- Normalize `turso://` → `https://` in `normaliseSQLiteUrl` before handing the URL to whichever driver was selected (currently it passes any URL with a protocol through unchanged)
- At minimum, print the `Using '...' driver` info line in the turso-remote path too, so the driver choice is visible
**Environment**: pnpm 10 workspace / monorepo, Node.js 22, macOS & Linux (CI), Turso Cloud (remote database).
Contributor guide
Research direction
Start in bin.cjs at connectToTursoRemote and checkPackage, then inspect normaliseSQLiteUrl and the existing driver-info logging. Reproduce with the listed pnpm dependencies and a turso:// URL, comparing behavior when @libsql/client is resolvable versus only @tursodatabase/serverless. Done means the driver selection is appropriate and the reported CI failure no longer occurs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, sqlite, typescript
- Domain
- cli, database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100