---
title: "Delete"
description: "Deleting data using Tauri SQLite ORM."
canonical_url: "https://docs.ctrl-neo.dev/en/tauri-sqlite-orm/querying-data/deleting-data"
---
# Delete

> Deleting data using Tauri SQLite ORM.

The `db.delete()` method allows you to remove records from your database. Like UPDATE, it requires careful use to avoid accidentally deleting all your data.

## Basic Delete

To delete records, use `.where()` to specify which rows to remove:

```ts
import { db } from '$lib/db';
import { users } from '$lib/db/schema';
import { eq } from '@type32/tauri-sqlite-orm';

// Delete a specific user
await db.delete(users)
  .where(eq(users._.columns.id, 1))
  .execute();
```

## WHERE Clause Validation

**Critical:** DELETE queries **require** a WHERE clause by default to prevent accidental data loss.

```ts
// ❌ This will throw an error!
await db.delete(users).execute();
// Error: DELETE operation on table "users" requires a WHERE clause

// ✅ This works - has a WHERE clause
await db.delete(users)
  .where(eq(users._.columns.id, 123))
  .execute();
```

### Intentional Global Deletes

If you genuinely want to delete all rows, use `.allowGlobalOperation()`:

```ts
// Clear all temporary cache - explicitly allowed
await db.delete(tempCache)
  .allowGlobalOperation()
  .execute();
```

## Conditional Deletes

Use operators to delete based on complex conditions:

```ts
import { and, lt, eq } from '@type32/tauri-sqlite-orm';

// Delete old, inactive users
await db.delete(users)
  .where(
    and(
      lt(users._.columns.lastLogin, oneYearAgo),
      eq(users._.columns.isActive, false)
    )
  )
  .execute();

// Delete unpublished drafts older than 30 days
await db.delete(posts)
  .where(
    and(
      eq(posts._.columns.status, 'draft'),
      lt(posts._.columns.createdAt, thirtyDaysAgo)
    )
  )
  .execute();
```

## Returning Deleted Data

Use `.returning()`, `.returningAll()`, or `.returningFirst()` to get the deleted records before they're removed:

### `.returningFirst()` - For Single Row Deletes

When deleting a single record, use `.returningFirst()` for cleaner code:

```ts
// ✅ Clean - returns single object
const deletedUser = await db.delete(users)
  .where(eq(users._.columns.id, 1))
  .returningFirst();

if (deletedUser) {
  console.log('Deleted user:', deletedUser.fullName, deletedUser.email);
  // Could log this for audit purposes
}
// Type: InferSelectModel<typeof users> | undefined
```

### `.returningAll()` - For Multiple Rows

When deleting multiple records:

```ts
// Get all deleted user data
const deletedUsers = await db.delete(users)
  .where(eq(users._.columns.status, 'banned'))
  .returningAll();

console.log(`Deleted ${deletedUsers.length} banned users`);
// Type: InferSelectModel<typeof users>[]
```

### `.returning()` - For Specific Columns

Return only the columns you need:

```ts
// Return specific columns only
const deletedInfo = await db.delete(users)
  .where(eq(users._.columns.status, 'banned'))
  .returning('id', 'email')
  .execute();
```

## Soft Deletes

Instead of actually deleting rows, you might want to mark them as deleted (soft delete):

```ts
// Instead of deleting, mark as deleted
await db.update(users)
  .set({ 
    deletedAt: new Date(),
    isDeleted: true 
  })
  .where(eq(users._.columns.id, userId))
  .execute();

// Query only non-deleted users
const activeUsers = await db.select(users)
  .where(eq(users._.columns.isDeleted, false))
  .all();
```

## Cascade Deletes

SQLite supports foreign key constraints with CASCADE. Define them in your schema:

```ts
import { sqliteTable, integer, text } from '@type32/tauri-sqlite-orm';

export const users = sqliteTable('users', {
  id: integer('id').primaryKey().autoincrement(),
  name: text('name').notNull(),
});

export const posts = sqliteTable('posts', {
  id: integer('id').primaryKey().autoincrement(),
  title: text('title').notNull(),
  authorId: integer('author_id').notNull().references(() => users._.columns.id),
  // When a user is deleted, their posts will also be deleted (if CASCADE is enabled in SQLite)
});
```

## Best Practices

1. **Always use WHERE clauses** - Prevents accidental data loss
2. **Consider soft deletes** - For user data that might need recovery
3. **Use .returningAll() for audit logs** - Keep track of what was deleted
4. **Test delete operations** - Verify you're deleting the right data
5. **Use transactions for related deletes** - Ensure atomicity

## Example: Safe User Deletion

```ts
async function deleteUser(userId: number) {
  // 1. Check if user exists
  const user = await db.select(users)
    .where(eq(users._.columns.id, userId))
    .first();

  if (!user) {
    throw new Error('User not found');
  }
  
  // 2. Delete in a transaction to ensure atomicity
  return await db.transaction(async (tx) => {
    // Delete user's posts
    await tx.delete(posts)
      .where(eq(posts._.columns.authorId, userId))
      .execute();
    
    // Delete the user and return their data (single record)
    const deletedUser = await tx.delete(users)
      .where(eq(users._.columns.id, userId))
      .returningFirst();
    
    if (!deletedUser) {
      throw new Error('Delete failed');
    }
    
    return deletedUser;
  });
}
```

## Example: Cleanup Old Records

```ts
async function cleanupOldRecords() {
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  
  // Delete old temporary files
  const result = await db.delete(tempFiles)
    .where(lt(tempFiles._.columns.createdAt, thirtyDaysAgo))
    .execute();
  
  console.log(`Deleted ${result[0].rowsAffected} old files`);
}
```

## Response Format

Without `.returning()`, delete operations return the number of affected rows:

```ts
const result = await db.delete(users)
  .where(eq(users._.columns.id, 1))
  .execute();

console.log(result);
// [{ rowsAffected: 1 }]
```


## Sitemap

See the full [sitemap](https://docs.ctrl-neo.dev/sitemap.md) for all pages.
