# Delete Hooks (https://s3.dimah.dev/docs/server/hooks/delete)



Enable object deletion with `delete: true` or a `DeleteConfig` object on a [named route](https://s3.dimah.dev/docs/server/routes).

<Callout>
  Unlike upload and download, object deletion is executed directly on your
  server using `DeleteObjectCommand` after passing `guard` checks. The client
  never deletes from S3 directly.
</Callout>

```ts title="lib/s3.ts"
import { S3Client } from "@aws-sdk/client-s3";
import { dimahS3, errors, route } from "@dimah-s3/server";

export const awsS3 = new S3Client({/* env */});

export const s3 = dimahS3({
  client: awsS3,
  bucket: process.env.S3_BUCKET!,
  routes: {
    avatar: route({
      delete: {
        guard: async ({ key, request }) => {
          const session = await getSession(request);
          if (!session) throw errors.unauthorized();

          const isOwner = await checkAvatarOwnership(session.userId, key);
          if (!isOwner) throw errors.forbidden();
        },
        onDeleted: async ({ key, request }) => {
          const session = await getSession(request);
          await db.user.update({
            where: { id: session.userId },
            data: { avatarKey: null },
          });
        },
      },
    }),
  },
});
```

***

## Delete lifecycle flow [#delete-lifecycle-flow]

<Flow
  label="Delete flow"
  steps="[
  { name: &#x22;delete.guard&#x22;, kind: &#x22;hook&#x22; },
  { name: &#x22;DeleteObject in S3&#x22;, kind: &#x22;s3&#x22; },
  { name: &#x22;onDeleted&#x22;, kind: &#x22;hook&#x22;, note: &#x22;Database cleanup&#x22; },
]"
/>

***

## Type reference [#type-reference]

```ts
import type {
  DeleteGuardContext,
  DeleteOnDeletedContext,
} from "@dimah-s3/server";
```

### DeleteGuardContext [#deleteguardcontext]

<AutoTypeTable path="packages/server/src/types/hook-contexts.ts" name="DeleteGuardContext" />

***

### DeleteOnDeletedContext [#deleteondeletedcontext]

<AutoTypeTable path="packages/server/src/types/hook-contexts.ts" name="DeleteOnDeletedContext" />

## Frequently asked questions [#frequently-asked-questions]

<Accordions>
  <Accordion title="How do I support batch deletion for multiple files?">
    Batch deletion (`deleteMany` / `removeMany`) runs `delete.guard` for each target key, calls S3 `DeleteObjects`, and triggers `onDeleted` for all successfully removed keys:

    ```ts title="Client usage"
    const { removeMany } = useDelete({ route: "avatar" });
    await removeMany([key1, key2]);
    ```
  </Accordion>

  <Accordion title="What happens if the S3 delete fails?">
    If S3 returns an error during deletion, `onDeleted` does not execute and the endpoint returns an appropriate error response (`502 S3_NETWORK_ERROR` or `INTERNAL_ERROR`).
  </Accordion>
</Accordions>
