# How to Perform Bulk Task Operations and Imports in Kaneo

> Streamline your workflow with Kaneo's bulk task API. Effortlessly update statuses, assignments, labels, and delete multiple tasks simultaneously using a single PATCH request to /api/task/bulk.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: how-to-guide
- Published: 2026-08-06

---

**Kaneo's bulk-task API lets you apply status changes, assignments, labels, and deletions to multiple tasks at once via a single PATCH request to `/api/task/bulk`.**

Kaneo is an open-source project management platform that treats bulk actions as first-class citizens. Whether you're cleaning up completed tasks, reassigning an entire sprint, or importing work from an external system, the **bulk operations architecture** in Kaneo makes mass updates efficient and permission-aware. This guide walks through the API design, frontend integration, and practical patterns for bulk task operations and imports.

## Understanding Kaneo's Bulk Task API

The core bulk functionality lives in the **Bulk-Update-Tasks controller** at [`apps/api/src/task/controllers/bulk-update-tasks.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/task/controllers/bulk-update-tasks.ts). This controller handles the `PATCH /api/task/bulk` endpoint and validates every request against workspace membership before executing database operations.

### Request Payload Structure

Every bulk request requires three fields:

| Field | Type | Description |
|-------|------|-------------|
| `taskIds` | `string[]` | Array of task UUIDs to modify |
| `operation` | `string` | The operation to perform (see supported operations below) |
| `value` | `string \| null \| undefined` | Operation-specific value (omitted for `delete`) |

The controller enforces a critical constraint: **all tasks must belong to the same workspace**, and the requesting user must have access to that workspace. This prevents cross-tenant data leaks.

### Supported Bulk Operations

Kaneo supports seven distinct bulk operations as implemented in the controller:

| Operation | Required `value` | Effect on Tasks |
|-----------|------------------|-----------------|
| `updateStatus` | Column slug (`"planned"`, `"in-progress"`, `"done"`, etc.) | Moves tasks to a new board column |
| `updatePriority` | Priority string (`"low"`, `"medium"`, `"high"`) | Updates priority field |
| `updateAssignee` | User ID string or omitted | Reassigns to user or unassigns |
| `delete` | *None* | Permanently deletes selected tasks |
| `addLabel` | Label ID | Attaches label to each task |
| `removeLabel` | Label ID | Detaches label and syncs with GitHub/Gitea |
| `updateDueDate` | ISO 8601 date string or `null` | Sets or clears due dates |

After successful execution, the controller calls `publishEvent` for each affected task, ensuring real-time UI synchronization across connected clients.

## Frontend Architecture for Bulk Operations

The Kaneo web interface implements bulk actions through a coordinated system of React components, custom hooks, and fetchers.

### Component: Bulk Toolbar

The **Bulk Toolbar** ([`apps/web/src/components/bulk-selection/bulk-toolbar.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/components/bulk-selection/bulk-toolbar.tsx)) appears automatically when users select multiple tasks. It renders action buttons based on available operations and consumes the `useBulkOperations` hook.

### Hook: useBulkOperations

Located at [`apps/web/src/hooks/mutations/task/use-bulk-operations.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/hooks/mutations/task/use-bulk-operations.ts), this hook creates a collection of `useMutation` objects—one for each bulk operation type. Key responsibilities include:

- Wrapping API calls with loading/error states
- **Cache invalidation** for `tasks`, `projects`, and `labels` queries on success
- Returning strongly-typed `mutateAsync` functions for programmatic use

### Fetcher: bulkOperation

The low-level network call resides in [`apps/web/src/fetchers/task/bulk-operation.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/fetchers/task/bulk-operation.ts). It sends a PATCH request and throws JavaScript exceptions for HTTP errors, allowing consistent error handling upstream.

## Implementing Bulk Task Operations

### React Hook Examples

**Bulk archive (status update):**

```typescript
import { useBulkOperations } from "@/hooks/mutations/task/use-bulk-operations";

const { bulkArchive } = useBulkOperations();

async function archiveCompleted(taskIds: string[]) {
  await bulkArchive(taskIds);
  // Query cache automatically refreshes
}

```

**Bulk assign to user:**

```typescript
const { bulkAssign } = useBulkOperations();

await bulkAssign({ 
  taskIds: selectedIds, 
  userId: "usr_123abc" 
});

```

**Bulk add label:**

```typescript
const { bulkAddLabel } = useBulkOperations();

await bulkAddLabel({ 
  taskIds: selectedIds, 
  labelId: "lbl_456def" 
});

```

### Direct Fetcher Usage (Non-React)

For server-side scripts, CLI tools, or vanilla JavaScript:

```typescript
import bulkOperation from "@/fetchers/task/bulk-operation";

await bulkOperation({
  taskIds: ["task_a1", "task_b2", "task_c3"],
  operation: "updatePriority",
  value: "high"
});

```

## Importing Tasks with Bulk Operations

Kaneo does not expose a dedicated import endpoint. Instead, the recommended pattern combines **task creation** with **bulk application** of shared properties.

### Import Workflow

1. **Parse source data** (CSV, JSON, Trello export, etc.) on the client
2. **Create tasks individually** using `createTask` fetcher ([`apps/web/src/fetchers/task/create-task.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/fetchers/task/create-task.ts))
3. **Collect returned task IDs**
4. **Issue bulk operation** to apply common labels, assignments, or due dates

This two-phase approach leverages Kaneo's existing validation while minimizing API calls for property application.

### Import-Then-Bulk Example

```typescript
import { createTask } from "@/fetchers/task/create-task";
import bulkOperation from "@/fetchers/task/bulk-operation";

async function importFromTrello(cards: TrelloCard[]) {
  const newTaskIds: string[] = [];
  
  // Phase 1: Create individual tasks
  for (const card of cards) {
    const { id } = await createTask({
      title: card.name,
      description: card.desc,
      projectId: destinationProjectId
    });
    newTaskIds.push(id);
  }
  
  // Phase 2: Bulk-label all imports
  await bulkOperation({
    taskIds: newTaskIds,
    operation: "addLabel",
    value: "migrated-from-trello"
  });
  
  // Optional: Bulk assign to import owner
  await bulkOperation({
    taskIds: newTaskIds,
    operation: "updateAssignee",
    value: currentUserId
  });
}

```

## Key Implementation Files

| Purpose | Path |
|---------|------|
| API route registration | [`apps/api/src/task/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/task/index.ts) |
| Core bulk controller | [`apps/api/src/task/controllers/bulk-update-tasks.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/task/controllers/bulk-update-tasks.ts) |
| Bulk toolbar UI | [`apps/web/src/components/bulk-selection/bulk-toolbar.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/components/bulk-selection/bulk-toolbar.tsx) |
| Operations hook | [`apps/web/src/hooks/mutations/task/use-bulk-operations.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/hooks/mutations/task/use-bulk-operations.ts) |
| Network fetcher | [`apps/web/src/fetchers/task/bulk-operation.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/fetchers/task/bulk-operation.ts) |
| List view integration | [`apps/web/src/components/list-view/task-row.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/components/list-view/task-row.tsx) |
| Selection state | [`apps/web/src/store/bulk-selection.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/store/bulk-selection.ts) |

## Summary

- **Kaneo's bulk-task API** at `/api/task/bulk` supports seven operations: status, priority, assignee, delete, add/remove label, and due date updates
- **Workspace validation** ensures users can only affect tasks within accessible workspaces
- **Frontend integration** uses `useBulkOperations` hook with automatic cache invalidation
- **Import patterns** combine individual task creation with bulk property application for efficiency
- **Real-time sync** via `publishEvent` keeps all connected clients updated

## Frequently Asked Questions

### What is the payload limit for bulk operations?

The Kaneo source code does not enforce a hard limit on `taskIds` array length in [`bulk-update-tasks.ts`](https://github.com/usekaneo/kaneo/blob/main/bulk-update-tasks.ts), but practical limits depend on your database configuration and request timeout settings. For imports exceeding hundreds of tasks, consider batching into multiple requests.

### Can I undo a bulk delete operation?

No. The `delete` operation permanently removes tasks immediately, with no soft-delete or trash mechanism in the current implementation. Always verify your selection before executing bulk deletions.

### How do bulk operations handle partial failures?

The controller validates all task IDs against workspace membership before executing any database changes. If validation fails for any task, the entire request rejects with an error—operations are atomic at the request level.

### Is there built-in CSV import support?

Not directly. Kaneo expects you to parse CSV files client-side and use the standard task creation API followed by bulk operations. This design keeps the core API lean while enabling flexible import sources (CSV, JSON, XML, third-party APIs).