drizzle-team / drizzle-team/drizzle-orm

[BUG]: `migrate` command creates tables in the wrong postgres schema

Open
#5,889 6 comments 0 reactions 0 assignees View on GitHub
bug
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@beta.22

### What version of `drizzle-kit` are you using?

1.0.0@beta.22

### Other packages

_No response_

## Describe the Bug

### Affected Setups

* Drizzle ORM connecting to any PostgreSQL database
* *I only tested it using the `node-postgres` (`pg`) driver*

### What is the undesired behavior?

* **The Problem:** When `migrations.schema` inside `drizzle.config.ts` matches the postgres db username, `drizzle-kit migrate` creates **all user defined tables** on the `"$user"` schema, instead of the expected `"public"` schema. (EDITED)
* This does NOT happen, when `migrations.schema` is set to something other than the db username `"$user"`.
* **Side Effect:** The `schema` field inside `snapshot.json` still points to `"public"`, even though the tables were actually created on the `"drizzle"` schema.

### What are the steps to reproduce it?
0. Setup a postgres Database with the owner `drizzle`
1. Set `migrations.schema` in `drizzle.config.ts` to the same value as the db username that owns the db (`"drizzle"`):
```typescript
import { config } from "dotenv";
import { defineConfig } from "drizzle-kit";

config({ path: ".env" });

export default defineConfig({
schema: "./src/db/schema.ts",
out: "./src/db/migrations",
dialect: "postgresql",
dbCredentials: { url: process.env.DATABASE_URL! },
migrations: { schema: "drizzle" }, // Or just set it to what the db username is, they just have to be exactly the same
});

```

2. Define a standard table in `schema.ts` without using `pgSchema`:
```typescript
import { pgTable as table, text } from "drizzle-orm/pg-core";

export const user = table("user", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
});

```

3. Run `drizzle-kit generate`. Notice how the generated sql is correct: It's `"user"`, and NOT `"drizzle"."user"`

Generated SQL `src/db/migrations/[timestamp]/migration.sql`:
```sql
CREATE TABLE "user" (
"id" text PRIMARY KEY,
"name" text NOT NULL,
"email" text NOT NULL UNIQUE,
);

```

Snapshot `src/db/migrations/[timestamp]/snapshot.json`:
```jsonc
{
"version": "8",
"dialect": "postgres",
"id": "a03e228c-9e0f-4469-adfe-9692249ef1f9",
"prevIds": [
"00000000-0000-0000-0000-000000000000"
],
"ddl": [
{
"isRlsEnabled": false,
"name": "user",
"entityType": "tables",
"schema": "public", // <- notice EXPECTED schema
},
{
"type": "text",
/* [...] */
"name": "id",
"entityType": "columns",
"schema": "public", // <- notice EXPECTED schema
"table": "user"
},
{
"type": "text",
/* [...] */
"name": "name",
"entityType": "columns",
"schema": "public", // <- notice EXPECTED schema
"table": "user"
},
{
"type": "text",
/* [...] */
"name": "email",
"entityType": "columns",
"schema": "public", // <- notice EXPECTED schema
"table": "user"
}
/* [... ETC ...] */
],
"renames": []
}
```

4. Now run `drizzle-kit migrate`.
5. Check the database relations using `\d` in `psql`. The `user` table will be defined on the `drizzle` schema, entirely contradicting the `snapshot.json` which defines it under `public`.

**DATABASE REALITY**:
```
List of relations
Schema | Name | Type | Owner
---------+-----------------------------+----------+---------
drizzle | __drizzle_migrations | table | drizzle
drizzle | __drizzle_migrations_id_seq | sequence | drizzle
drizzle | user | table | drizzle
^
INCORRECT
```

6. Optional: To prove that this only happens when `migrations.schema` is set to `"drizzle"`, execute `DROP DATABASE example;` and start again at step 1. But now set `migrations.schema` to something other than the db username or `"public"` and observe how the issue goes away. **BEWARE**: If you do not drop the database, the bug persists. Meaning, if you simply drop all the tables or the `"drizzle"` schema, and then re-run the migrations using `drizzle-kit migrate`, then `migrations.schema` will keep controlling the schema of all user defined tables.

### What is the desired result?

**DESIRED RESULT**:
```
List of relations
Schema | Name | Type | Owner
---------+-----------------------------+----------+---------
drizzle | __drizzle_migrations | table | drizzle
drizzle | __drizzle_migrations_id_seq | sequence | drizzle
public | user | table | drizzle
^
CORRECT
```

1. The `migrations.schema` configuration property should **only ever** dictate the schema for Drizzle's internal migration tables and sequences, namely: the `__drizzle_migrations` table and the `__drizzle_migrations_id_seq` sequence

2. Application tables defined without an explicit `pgSchema` layout should ALWAYS respect the database driver's native environment or fallback to `public`, instead of the schema specified in `config.migrations.schema`.

3. The generated `snapshot.json` should always be in sync with what gets actually created in the database (only the `schema` property is wrong in this case).

## Workarounds

### Workaround 1
Add the following code to the top of the generated `migration.sql` file:
```sql
CREATE SCHEMA IF NOT EXISTS public;
SET search_path TO public;

```

### Workaround 2
*(if you don't want to manually edit `migration.sql` files)*
Set `config.migrations.schema` to something other than `"drizzle"` (e.g. `"public"`), to create all tables on the public schema, and thus remove the schema mismatch between the database reality and the `snapshot.json` file.

## Related issues
- #5274
- The bug described in this issue, was likely an additional cause for #4369

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.