Bulk Operations

Nuxt Auto API provides atomic bulk operations for creating, updating, and deleting multiple records in a single request.

Bulk Operations

Nuxt Auto API provides atomic bulk operations for creating, updating, and deleting multiple records in a single request.

Overview

All bulk operations are:

  • Atomic: Use database transactions (rollback on any failure)
  • Authorized: Check permissions for each item
  • Validated: Validate each item before processing
  • Hooked: Execute lifecycle hooks for each item

Bulk Create

Create multiple records in a single request:

POST /api/users/bulk

{
  "items": [
    {
      "name": "John Doe",
      "email": "john@example.com"
    },
    {
      "name": "Jane Smith",
      "email": "jane@example.com"
    }
  ]
}

Response:

{
  "data": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com",
      "createdAt": "2024-01-01T00:00:00Z"
    },
    {
      "id": 2,
      "name": "Jane Smith",
      "email": "jane@example.com",
      "createdAt": "2024-01-01T00:00:00Z"
    }
  ],
  "meta": {
    "total": 2,
    "successful": 2,
    "failed": 0
  }
}

Bulk Update

Update multiple records by ID:

PATCH /api/users/bulk

{
  "items": [
    {
      "id": 1,
      "data": {
        "name": "John Updated"
      }
    },
    {
      "id": 2,
      "data": {
        "email": "jane.new@example.com"
      }
    }
  ]
}

Response:

{
  "data": [
    {
      "id": 1,
      "name": "John Updated",
      "email": "john@example.com",
      "updatedAt": "2024-01-01T00:01:00Z"
    },
    {
      "id": 2,
      "name": "Jane Smith",
      "email": "jane.new@example.com",
      "updatedAt": "2024-01-01T00:01:00Z"
    }
  ],
  "meta": {
    "total": 2,
    "successful": 2,
    "failed": 0
  }
}

Bulk Delete

Delete multiple records by ID:

DELETE /api/users/bulk

{
  "ids": [1, 2, 3]
}

Response:

{
  "data": [
    { "id": 1, "deleted": true },
    { "id": 2, "deleted": true },
    { "id": 3, "deleted": true }
  ],
  "meta": {
    "total": 3,
    "successful": 3,
    "failed": 0
  }
}

Transaction Behavior

By default, all bulk operations use database transactions:

// If ANY item fails, ALL changes are rolled back
PATCH /api/users/bulk

{
  "items": [
    { "id": 1, "data": { "name": "Valid" } },
    { "id": 999, "data": { "name": "Invalid ID" } }  // Fails
  ]
}

// Result: Neither update is applied (rollback)
{
  "statusCode": 400,
  "message": "Bulk update failed (transaction rolled back)",
  "data": {
    "errors": [
      {
        "index": 1,
        "id": 999,
        "error": "Record with id 999 not found"
      }
    ]
  }
}

Non-Transactional Mode

Disable transactions for partial success:

export default defineNuxtConfig({
  autoApi: {
    bulk: {
      transactional: false  // Allow partial success
    }
  }
})

With transactional: false:

PATCH /api/users/bulk

{
  "items": [
    { "id": 1, "data": { "name": "Valid" } },      // Succeeds
    { "id": 999, "data": { "name": "Invalid" } }   // Fails
  ]
}

// Result: First update succeeds, second fails
{
  "data": [
    {
      "id": 1,
      "name": "Valid",
      "updatedAt": "..."
    }
  ],
  "meta": {
    "total": 2,
    "successful": 1,
    "failed": 1,
    "errors": [
      {
        "index": 1,
        "id": 999,
        "error": "Record with id 999 not found"
      }
    ]
  }
}

Batch Size Limits

Protect your database from oversized requests:

export default defineNuxtConfig({
  autoApi: {
    bulk: {
      maxBatchSize: 100  // Default: 100
    }
  }
})

Exceeding the limit returns an error:

POST /api/users/bulk

{
  "items": [/* 150 items */]
}

// Response:
{
  "statusCode": 400,
  "message": "Batch size exceeds maximum of 100"
}

Authorization

Each item is individually authorized:

// User can only update their own records
PATCH /api/posts/bulk

{
  "items": [
    { "id": 1, "data": { "title": "My Post" } },      // User owns: ✅
    { "id": 2, "data": { "title": "Others Post" } }   // User doesn't own: ❌
  ]
}

// In transactional mode: entire request fails
// In non-transactional mode: only authorized items succeed

Lifecycle Hooks

Hooks execute for each item in the batch:

// server/plugins/user-hooks.ts
export default defineNitroPlugin(() => {
  const hooks = globalThis.__autoApiHooks || (globalThis.__autoApiHooks = {})

  hooks.users = {
    beforeCreate: async (data) => {
      console.log('Creating user:', data.email)
      // Set default values, validate, etc.
      data.role = data.role || 'user'
      return data
    },

    afterCreate: async (user) => {
      console.log('User created:', user.id)
      // Send welcome email, log audit, etc.
    }
  }
})

Bulk create triggers hooks for each item:

POST /api/users/bulk

{
  "items": [
    { "name": "User 1", "email": "user1@example.com" },
    { "name": "User 2", "email": "user2@example.com" }
  ]
}

// Console output:
// Creating user: user1@example.com
// Creating user: user2@example.com
// User created: 1
// User created: 2

Validation

Each item is validated before processing:

// With validation schema
export const userValidation = {
  create: z.object({
    name: z.string().min(2),
    email: z.string().email()
  })
}

// Request with validation errors
POST /api/users/bulk

{
  "items": [
    { "name": "Valid User", "email": "valid@example.com" },
    { "name": "X", "email": "invalid" }  // Validation fails
  ]
}

// In transactional mode: entire request fails
// In non-transactional mode: only valid items succeed

Frontend Usage

With Composables

// Bulk create
const { execute, data, error } = useAutoApiAction('users', 'bulk')

await execute({
  method: 'POST',
  body: {
    items: [
      { name: 'User 1', email: 'user1@example.com' },
      { name: 'User 2', email: 'user2@example.com' }
    ]
  }
})

console.log(data.value.meta)  // { total: 2, successful: 2, failed: 0 }
// Bulk update
const { execute } = useAutoApiAction('users', 'bulk')

await execute({
  method: 'PATCH',
  body: {
    items: [
      { id: 1, data: { name: 'Updated 1' } },
      { id: 2, data: { name: 'Updated 2' } }
    ]
  }
})
// Bulk delete
const { execute } = useAutoApiAction('users', 'bulk')

await execute({
  method: 'DELETE',
  body: {
    ids: [1, 2, 3]
  }
})

Direct Fetch

// Bulk create
const response = await $fetch('/api/users/bulk', {
  method: 'POST',
  body: {
    items: [...]
  }
})

// Bulk update
await $fetch('/api/users/bulk', {
  method: 'PATCH',
  body: {
    items: [
      { id: 1, data: { ... } }
    ]
  }
})

// Bulk delete
await $fetch('/api/users/bulk', {
  method: 'DELETE',
  body: {
    ids: [1, 2, 3]
  }
})

Use Cases

Data Import

// Import CSV data
const users = parseCSV(csvFile)

const { data } = await $fetch('/api/users/bulk', {
  method: 'POST',
  body: { items: users }
})

console.log(`Imported ${data.meta.successful} users`)

Batch Updates

// Mark multiple items as processed
const itemIds = [1, 2, 3, 4, 5]

await $fetch('/api/tasks/bulk', {
  method: 'PATCH',
  body: {
    items: itemIds.map(id => ({
      id,
      data: { status: 'completed', completedAt: new Date() }
    }))
  }
})

Cleanup Operations

// Delete old records
const oldRecordIds = await $fetch('/api/logs', {
  query: {
    filter: {
      createdAt: { $lt: '2023-01-01' }
    },
    fields: 'id'
  }
})

await $fetch('/api/logs/bulk', {
  method: 'DELETE',
  body: {
    ids: oldRecordIds.data.map(r => r.id)
  }
})

Configuration Reference

export default defineNuxtConfig({
  autoApi: {
    bulk: {
      // Enable/disable bulk operations (default: true)
      enabled: true,

      // Maximum items per batch (default: 100)
      maxBatchSize: 100,

      // Use transactions (default: true)
      transactional: true
    }
  }
})

Error Handling

Transactional Mode Errors

{
  "statusCode": 400,
  "message": "Bulk update failed (transaction rolled back)",
  "data": {
    "errors": [
      {
        "index": 1,
        "id": 999,
        "error": "Record with id 999 not found"
      }
    ]
  }
}

Non-Transactional Mode Errors

{
  "data": [/* successful items */],
  "meta": {
    "total": 5,
    "successful": 3,
    "failed": 2,
    "errors": [
      {
        "index": 1,
        "id": 999,
        "error": "Record not found"
      },
      {
        "index": 3,
        "error": "Validation failed"
      }
    ]
  }
}

Performance Considerations

Batch Size

Smaller batches = More requests but safer:

  • Recommended: 50-100 items per batch
  • Large imports: Split into multiple batches
// Split large dataset
const BATCH_SIZE = 100
const batches = chunk(largeDataset, BATCH_SIZE)

for (const batch of batches) {
  await $fetch('/api/users/bulk', {
    method: 'POST',
    body: { items: batch }
  })
}

Indexes

Ensure indexes exist for bulk updates/deletes:

-- Primary key index (usually automatic)
CREATE INDEX idx_users_id ON users(id);

-- For tenant-scoped bulk operations
CREATE INDEX idx_users_org_id ON users(organization_id);

Memory Usage

Large batches consume memory:

  • Server: Holds all items in memory during transaction
  • Client: JSON serialization/parsing overhead

Multi-Tenancy

Bulk operations respect tenant scoping:

// Automatically scoped to current tenant
POST /api/users/bulk

{
  "items": [
    { "name": "User 1", "email": "user1@example.com" }
    // organizationId automatically added
  ]
}

// Can only update/delete records in current tenant
PATCH /api/users/bulk
DELETE /api/users/bulk

Soft Deletes

Bulk delete respects soft delete configuration:

// If soft deletes are enabled
DELETE /api/users/bulk

{
  "ids": [1, 2, 3]
}

// Records are marked as deleted, not physically removed
// deletedAt timestamp is set

Best Practices

  1. Use transactions: Keep transactional: true for data integrity
  2. Limit batch size: Don't exceed 100-200 items per request
  3. Handle errors: Check meta.failed and meta.errors in responses
  4. Validate upfront: Validate data before sending bulk requests
  5. Use hooks: Implement audit logging in after* hooks
  6. Monitor performance: Track bulk operation duration and optimize
  7. Split large imports: Break into smaller batches with progress tracking

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.