npm sqs-consumer 14.0.0-canary.1
v14.0.0-canary.1

latest release: 14.0.0-canary.2
one day ago

14.0.0-canary.1 (2025-08-31)

SQS Consumer v14.0.0 Migration Guide

Overview

Version 14.0.0 introduces a breaking change to how message acknowledgment works. This change makes acknowledgment behavior more explicit and predictable, addressing user confusion about when messages are acknowledged.

What Changed

Previous Behavior (<=v13.x)

  • Messages were acknowledged automatically in certain scenarios
  • Returning void (nothing) from handlers had implicit acknowledgment behavior
  • Users were often unclear about when messages would be acknowledged

New Behavior (>=v14.0)

  • Explicit acknowledgment only: Messages are acknowledged only when explicitly returned
  • Returning void (nothing) means no acknowledgment by default
  • Clear, predictable behavior based on what your handler returns

Benefits of the New Approach

  • Clarity: Explicit acknowledgment makes code intent clear
  • Reliability: Reduce accidental acknowledgment of failed processing
  • Debugging: Easier to trace acknowledgment behavior
  • Flexibility: Fine-grained control over which messages are acknowledged

Migration Steps

handleMessage()

Step 1: Identify Your Current Handler Pattern

First, determine which pattern your current message handlers follow:

// Pattern A: Handler that processes and implicitly acknowledges
const handleMessage = async (message) => {
  await processMessage(message);
  // No explicit return - was implicitly acknowledged in v13.x
};

// Pattern B: Handler with conditional acknowledgment
const handleMessage = async (message) => {
  const success = await processMessage(message);
  if (success) {
    return message; // Only acknowledge on success
  }
  // Don't acknowledge on failure
};


// Pattern C: Error handling
const handleMessage = async (message) => {
  try {
    await processMessage(message);
  } catch (error) {
    // Message acknowledgment behavior was unclear
    throw error;
  }
};

Step 2: Update Your Handlers

For Pattern A (Implicit Acknowledgment)

Option 1: Explicit Return

const consumer = Consumer.create({
  queueUrl: 'your-queue-url',
  handleMessage: async (message) => {
    console.log('Processing:', message.Body);
    await processMessage(message);
    return message; // Explicit acknowledgment
  }
});

Option 2: Use alwaysAcknowledge

const consumer = Consumer.create({
  queueUrl: 'your-queue-url',
  alwaysAcknowledge: true, // Maintains v13.x behavior
  handleMessage: async (message) => {
    console.log('Processing:', message.Body);
    await processMessage(message);
    // Will be acknowledged due to alwaysAcknowledge setting
  }
});

For Pattern B and C (Conditional Acknowledgment)

const consumer = Consumer.create({
  queueUrl: 'your-queue-url',
  handleMessage: async (message) => {
    try {
      await processMessage(message);
      return message; // Acknowledge on success
    } catch (error) {
      console.error('Processing failed:', error);
      // Don't return anything - message won't be acknowledged
      // It will be retried based on your queue's redrive policy
    }
  }
});

handleMessageBatch()

This is largely similar to the above recommendations, you just need to adjust to build up an array of the messages that you want to acknowledge and then return that array.

const handleMessageBatch = async (messages) => {
  const processed = [];
  
  for (const message of messages) {
    try {
      await processMessage(message);
      processed.push(message); // Add to acknowledgment list
    } catch (error) {
      console.error('Failed to process message:', error);
      // Don't add to processed array - won't be acknowledged
    }
  }
  
  return processed; // Only acknowledge successfully processed messages
};

Configuration Options

alwaysAcknowledge Setting

Use this setting to maintain <=v13.x behavior during migration:

const consumer = Consumer.create({
  queueUrl: 'your-queue-url',
  alwaysAcknowledge: true, // Messages acknowledged regardless of return value
  handleMessage: async (message) => {
    await processMessage(message);
    // Will be acknowledged due to alwaysAcknowledge: true
  }
});

⚠️ Warning: alwaysAcknowledge: true should be used as a temporary migration aid. The explicit return pattern is recommended for long-term maintainability.

Don't miss a new sqs-consumer release

NewReleases is sending notifications on new releases.