Skip to content

DartQL Recipes

Practical DartQL recipes you can copy, adapt, and run. Each recipe uses execute_dartql, the preferred tool for batch operations. Always start with dry_run: true (the default) to preview before executing.

Move all in-progress tasks to done at the end of a sprint:

UPDATE WHERE dartboard = 'Engineering/sprint-12' AND status = 'Doing'
SET status = 'Done'
COMMENT 'Sprint 12 closed: {title}'

Tip: The {title} template variable inserts each task’s title into the comment automatically.

Assign all unassigned high-priority backend tasks to a specific engineer:

UPDATE WHERE dartboard = 'Engineering/backend'
AND priority = 4
AND assignee IS NULL
SET assignees = ['engineer@company.com']

Apply a due date to all tasks in the current sprint that don’t have one:

UPDATE WHERE dartboard = 'Engineering/sprint-13'
AND due_at IS NULL
SET due_at = '2026-02-14T00:00:00Z'

Escalate overdue tasks that are still open:

UPDATE WHERE due_at < '2026-04-09T00:00:00Z'
AND status != 'Done'
AND priority = 4
SET priority = 5
COMMENT 'Auto-escalated: overdue'

Move all tasks completed in Q1 to an archive dartboard:

UPDATE WHERE completed_at >= '2026-01-01T00:00:00Z'
AND completed_at < '2026-04-01T00:00:00Z'
SET dartboard = 'Archive/2026-Q1'

Tip: Use concurrency: 10 for large batches to speed up execution.

Remove tasks that haven’t been updated in months and are still in the backlog:

DELETE WHERE priority = 1
AND updated_at < '2025-10-01T00:00:00Z'
AND status = 'To Do'
CONFIRM

Safety: The CONFIRM keyword is required for DELETE statements when dry_run is false. Without it, the statement is rejected.

Find tasks marked as duplicates and delete them:

DELETE WHERE duplicate_ids IS NOT NULL CONFIRM

Archive done tasks and delete abandoned ones in a single call:

UPDATE WHERE status = 'Done' AND dartboard = 'Engineering/backend'
SET dartboard = 'Archive/2026-Q1';
DELETE WHERE status = 'To Do'
AND updated_at < '2025-07-01T00:00:00Z'
AND priority = 1
CONFIRM

Tip: Semicolons separate statements. Each runs independently, so a failure in one does not block the others.

Use list_tasks or batch_update_tasks with dry_run: true to query without changing anything:

UPDATE WHERE blocker_ids IS NOT NULL
SET tags = ['blocked-review']

Run this as a dry run first to see which tasks have blockers. If you want to tag them for tracking, execute with dry_run: false.

Find tasks created during a specific period:

UPDATE WHERE created_at BETWEEN '2026-03-01T00:00:00Z' AND '2026-03-31T23:59:59Z'
SET tags = ['march-audit']

Identify critical tasks with no owner:

UPDATE WHERE priority = 5
AND assignee IS NULL
SET tags = ['needs-owner']

Find tasks matching a keyword pattern:

UPDATE WHERE title LIKE '%authentication%'
AND status != 'Done'
SET tags = ['auth-related']

Tip: LIKE uses SQL-92 wildcards: % matches any characters, _ matches a single character. Matching is case-insensitive.

Mark critical tasks as blocking a release:

UPDATE WHERE priority = 5 AND status != 'Done'
SET blocking_ids = ['duid_release_v2']

Important: Relationship arrays use full replacement. This sets blocking_ids to exactly the value provided, replacing any previous values.

Unblock all tasks in a dartboard after a dependency ships:

UPDATE WHERE dartboard = 'Engineering/frontend'
AND blocker_ids IS NOT NULL
SET blocker_ids = []

Tip: An empty array [] clears all relationships of that type.

Tag and link all security-related tasks to an audit tracker:

UPDATE WHERE tags CONTAINS 'security'
SET related_ids = ['duid_security_audit_2026'],
priority = 5

Identify tasks that have children:

UPDATE WHERE subtask_ids IS NOT NULL
AND tags CONTAINS 'epic'
SET tags = ['epic', 'has-subtasks']

Query which tasks depend on a particular blocker:

UPDATE WHERE blocker_ids CONTAINS 'duid_infra_migration'
SET tags = ['awaiting-infra']

Use import_tasks_csv with column mapping to create tasks from a CSV file:

// Step 1: Validate without creating anything
import_tasks_csv({
csv_file_path: "./backlog.csv",
dartboard: "Engineering/backend",
column_mapping: {
"Summary": "title",
"Details": "description",
"Owner Email": "assignee",
"Priority Level": "priority",
"Labels": "tags"
},
validate_only: true
})
// Step 2: Review validation results, then import
import_tasks_csv({
csv_file_path: "./backlog.csv",
dartboard: "Engineering/backend",
column_mapping: {
"Summary": "title",
"Details": "description",
"Owner Email": "assignee",
"Priority Level": "priority",
"Labels": "tags"
},
validate_only: false
})

Tip: Always call get_config() first to see valid dartboard names, priorities, and statuses for your workspace.

After importing, tag the batch so you can manage them together:

UPDATE WHERE dartboard = 'Engineering/backend'
AND tags CONTAINS 'imported'
SET priority = 3

Add an imported tag column in your CSV, or use the default_values parameter during import to auto-tag.

  • API-compatible selectors are faster. Simple = on assignee, status, dartboard, priority, and tags goes directly to the Dart API. Complex operators like OR, LIKE, IN, and BETWEEN require client-side filtering (fetches all tasks first).
  • Use concurrency to control throughput. Default is 5; increase to 10-20 for large batches, decrease to 1-2 if hitting rate limits.
  • Dry run first, always. dry_run: true is the default. Preview your selector matches before executing any mutation.
  • Multi-statement batches run statements sequentially. Put the most important operation first.