drizzle-team / drizzle-team/drizzle-orm

[BUG]: SQLite push generates DEFAULT datetime('now') without parentheses, causing syntax error

Open
#5,634 2 comments 0 reactions 0 assignees View on GitHub
enhancement
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.21

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

1.0.0-beta.21

### Other packages

_No response_

### Describe the Bug

When drizzle-kit push recreates a SQLite table (e.g., to add a named UNIQUE constraint), it generates DEFAULT
datetime('now') instead of DEFAULT (datetime('now')) in the CREATE TABLE statement. SQLite requires parentheses around
expression defaults, so this produces a syntax error:

SQLITE_ERROR: near "(": syntax error

Expected behavior

The generated SQL should wrap expression defaults in parentheses:

`created_at` text DEFAULT (datetime('now'))

Actual behavior

The generated SQL omits the outer parentheses:

`created_at` text DEFAULT datetime('now')

The full generated statement:

```sql
CREATE TABLE `__new_fundraiser_updates` (
`id` integer PRIMARY KEY AUTOINCREMENT,
`fundraiser_id` integer NOT NULL,
`created_at` text DEFAULT datetime('now'),
`url` text,
CONSTRAINT `fundraiser_updates_fundraiser_url_unique` UNIQUE(`fundraiser_id`,`url`)
);
```

Steps to reproduce

Schema definition (schema.ts):

```ts
import { sqliteTable, integer, text, unique } from "drizzle-orm/sqlite-core";
import { sql } from "drizzle-orm";

export const fundraiserUpdates = sqliteTable(
"fundraiser_updates",
{
id: integer().primaryKey({ autoIncrement: true }),
fundraiserId: integer("fundraiser_id").notNull(),
createdAt: text("created_at").default(sql`datetime('now')`),
url: text(),
},
(t) => [
unique("fundraiser_updates_fundraiser_url_unique").on(
t.fundraiserId,
t.url
),
]
);
```

Seed the database with an unnamed UNIQUE constraint (reproduce.ts):

```ts
import { createClient } from "@libsql/client";

const client = createClient({ url: "file:./test.db" });

await client.execute(`
CREATE TABLE IF NOT EXISTS fundraiser_updates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
fundraiser_id INTEGER NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
url TEXT,
UNIQUE (fundraiser_id, url)
);
`);
```

Trigger the bug:

npx tsx reproduce.ts
npx drizzle-kit push --force

The existing table has an unnamed UNIQUE (fundraiser_id, url) constraint. The schema defines a named one
(fundraiser_updates_fundraiser_url_unique), so drizzle-kit push recreates the table. During recreation, it reads the
existing DEFAULT (datetime('now')) from SQLite metadata, strips the outer parentheses, and doesn't re-add them in the
generated CREATE TABLE.

Environment

- Database: SQLite via @libsql/client
- OS: Windows 11
- drizzle-orm: 1.0.0-beta.21
- drizzle-kit: 1.0.0-beta.21

Contributor guide

Open the contributing guide

Research direction

Start with schema.ts and reproduce.ts, then run npx tsx reproduce.ts and npx drizzle-kit push --force to observe the SQLite table recreation. Trace the drizzle-kit path that reads the existing DEFAULT (datetime('now')) and emits the CREATE TABLE statement. Done when the recreated table uses DEFAULT (datetime('now')) and push completes without SQLITE_ERROR.

Written by the indexing model from the issue text.

Assessment

Tech stack
sqlite, typescript
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.