Skip to main content

Description

Decrements the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that cannot be represented as an integer.

Syntax

redis.decr(key: string): Promise<number>

Parameters

key
string
required
The key containing the integer to decrement

Returns

value
number
The value of the key after the decrement

Examples

Basic Usage

import { Redis } from '@upstash/redis';

const redis = new Redis({
  url: 'https://your-redis-url.upstash.io',
  token: 'your-token'
});

// Set an initial value
await redis.set('counter', 10);

// Decrement by 1
const newValue = await redis.decr('counter');
console.log(newValue); // 9

const value = await redis.get('counter');
console.log(value); // "9"

Decrement Non-Existent Key

// Decrementing a non-existent key initializes it to 0 and then decrements
const result = await redis.decr('newcounter');
console.log(result); // -1

Multiple Decrements

await redis.set('inventory', 100);

// Decrement multiple times
await redis.decr('inventory'); // 99
await redis.decr('inventory'); // 98
await redis.decr('inventory'); // 97

const remaining = await redis.get('inventory');
console.log(remaining); // "97"

Inventory Management

// Track product inventory
async function sellProduct(productId: string, quantity: number = 1) {
  for (let i = 0; i < quantity; i++) {
    const remaining = await redis.decr(`product:${productId}:stock`);
    if (remaining < 0) {
      // Rollback - increment back
      await redis.incr(`product:${productId}:stock`);
      throw new Error('Out of stock');
    }
  }
}

// Initialize stock
await redis.set('product:123:stock', 5);

// Sell 2 items
await sellProduct('123', 2);
const stock = await redis.get('product:123:stock');
console.log(stock); // "3"

Countdown Timer

// Set up a countdown
await redis.set('countdown', 10);

const interval = setInterval(async () => {
  const remaining = await redis.decr('countdown');
  console.log(`${remaining} seconds remaining`);
  
  if (remaining <= 0) {
    clearInterval(interval);
    console.log('Countdown complete!');
  }
}, 1000);

Rate Limiting (Remaining Credits)

// Initialize user credits
await redis.set('user:123:credits', 100);

async function useCredit(userId: string): Promise<number> {
  const remaining = await redis.decr(`user:${userId}:credits`);
  
  if (remaining < 0) {
    // Rollback and throw error
    await redis.incr(`user:${userId}:credits`);
    throw new Error('Insufficient credits');
  }
  
  return remaining;
}

try {
  const credits = await useCredit('123');
  console.log(`${credits} credits remaining`);
} catch (error) {
  console.error(error.message);
}

Download Counter

// Track remaining downloads
async function trackDownload(fileId: string) {
  const remaining = await redis.decr(`file:${fileId}:downloads:remaining`);
  
  if (remaining < 0) {
    await redis.incr(`file:${fileId}:downloads:remaining`);
    return { allowed: false, remaining: 0 };
  }
  
  return { allowed: true, remaining };
}

// Set initial download limit
await redis.set('file:abc:downloads:remaining', 3);

const result1 = await trackDownload('abc');
console.log(result1); // { allowed: true, remaining: 2 }

const result2 = await trackDownload('abc');
console.log(result2); // { allowed: true, remaining: 1 }

Seat Reservation System

// Initialize available seats
await redis.set('event:concert:seats', 100);

async function reserveSeat(eventId: string): Promise<{ success: boolean; seatsLeft: number }> {
  const seatsLeft = await redis.decr(`event:${eventId}:seats`);
  
  if (seatsLeft < 0) {
    // No seats available, rollback
    await redis.incr(`event:${eventId}:seats`);
    return { success: false, seatsLeft: 0 };
  }
  
  return { success: true, seatsLeft };
}

const reservation = await reserveSeat('concert');
if (reservation.success) {
  console.log(`Seat reserved! ${reservation.seatsLeft} seats remaining`);
} else {
  console.log('Sorry, event is sold out');
}

Notes

  • This is an atomic operation, making it safe for concurrent decrements
  • The value must be an integer or a string that can be parsed as an integer
  • If the key contains a non-integer value, an error will be returned
  • The operation has O(1) time complexity
  • The range of values is limited to 64-bit signed integers
  • Decrementing below zero is allowed (will result in negative numbers)

Error Handling

try {
  // This will throw an error because "hello" is not a valid integer
  await redis.set('mykey', 'hello');
  await redis.decr('mykey');
} catch (error) {
  console.error('Cannot decrement non-integer value');
}
  • incr - Increment the integer value of a key by one

Redis Documentation

For more information, see the Redis DECR documentation.

Build docs developers (and LLMs) love