drizzle-team / drizzle-team/drizzle-orm
[BUG]: `migrate` command creates tables in the wrong postgres schema
- 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
Assessment
This issue has not been assessed yet.