drizzle-team / drizzle-team/drizzle-orm
[BUG]: drizzle-kit push (pg): numeric index .with() params never match text reloptions — index dropped and rebuilt on every push
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### What version of drizzle-orm are you using?
0.45.2
### What version of drizzle-kit are you using?
0.31.10
### Describe the Bug
Declaring Postgres index storage parameters (`.with()`) with **numeric** values makes `drizzle-kit push` DROP and re-CREATE that index on **every** push, forever:
```ts
index('chunk_embedding_hnsw_idx')
.using('hnsw', t.embedding.op('vector_cosine_ops'))
.with({ m: 24, ef_construction: 128 }),
```
Every push (no schema changes) emits:
```sql
DROP INDEX "chunk_embedding_hnsw_idx";
CREATE INDEX "chunk_embedding_hnsw_idx" ON "chunk" USING hnsw ("embedding" vector_cosine_ops) WITH (m=24,ef_construction=128);
```
Postgres reloptions introspect as text — the DB-side snapshot holds `{"m": "24", "ef_construction": "128"}` — while the schema side serializes numbers (`{"m": 24, ...}`), so the comparison never matches.
In practice this is dangerous, not just noisy: an HNSW rebuild over a few hundred thousand pgvector rows is many minutes of zero-output "hang" on every push, and interrupting the seemingly-frozen push leaves the database **without the index** (ours ran on seq scan until we noticed).
### Workaround
Declare the params as strings — `.with({ m: '24', ef_construction: '128' })` — the diff goes quiet immediately.
### Suggested fix
Normalize `with` values before comparing in the differ (stringify both sides, or coerce introspected reloptions to numbers). The type accepted by `.with()` could also be narrowed/documented to strings to make the footgun impossible.
Contributor guide
Research direction
Start by reproducing the issue with drizzle-kit push and a Postgres index using numeric .with() values, then inspect the differ's comparison between schema-side values and the database snapshot's text reloptions. Done means repeated pushes with no schema changes emit no DROP/CREATE for the index and leave the index intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, typescript
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100