Skip to content

Atomic numeric operations

Atomic numeric operations allow you to safely increase or decrease numeric fields without fetching the full document. This eliminates race conditions and reduces bandwidth usage when updating any numeric values that need to be modified atomically, such as counters, scores, balances, and other fast-moving numeric data.

How atomic operations work

Instead of the traditional read-modify-write pattern, atomic numeric operations use dedicated methods to modify values directly on the server. The server applies the change atomically under concurrency control and returns the new value.

Traditional approach:

  1. Fetch document → { likes: 42 }
  2. Update client-side → likes: 43
  3. Write back → { likes: 43 }

Atomic approach:

  1. Call incrementDocumentColumn() with the column name and the value to increment by
  2. Server applies atomically → likes: 43

When to use atomic operations

Atomic numeric operations work well for:

  • Social features: Likes, follows, comment counts
  • Usage metering: API credits, storage quotas, request limits
  • Game state: Scores, lives, currency, experience points
  • E-commerce: Stock counts, inventory levels
  • Workflow tracking: Retry counts, progress indicators
  • Rate limiting: Request counters, usage tracking

Perform atomic operations

Use the incrementDocumentColumn and decrementDocumentColumn methods to perform atomic numeric operations. The server will apply these changes atomically under concurrency control.

Increment a field

import { Client, Databases } from "appwrite";

const client = new Client()
    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
    .setProject('<YOUR_PROJECT_ID>'); // Your project ID

const databases = new Databases(client);

const result = await databases.incrementDocumentColumn(
    '<DATABASE_ID>',
    '<COLLECTION_ID>',
    '<DOCUMENT_ID>',
    'likes', // column
    1 // value
);

Decrement a field

Use the decrementDocumentColumn method to decrease numeric fields:

import { Client, Databases } from "appwrite";

const client = new Client()
    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
    .setProject('<YOUR_PROJECT_ID>'); // Your project ID

const databases = new Databases(client);

const result = await databases.decrementDocumentColumn(
    '<DATABASE_ID>',
    '<COLLECTION_ID>',
    '<DOCUMENT_ID>',
    'credits', // column
    5 // value
);

Set constraints and bounds

You can set minimum and maximum bounds for individual operations to prevent invalid values. Use the optional min and max parameters to ensure the final value stays within accepcollection limits:

Example with constraints

// Increment with maximum constraint
const result = await databases.incrementDocumentColumn(
    '<DATABASE_ID>',
    '<COLLECTION_ID>',
    '<DOCUMENT_ID>',
    'credits', // column
    100, // value
    1000 // max (optional)
);

// Decrement with minimum constraint
const result2 = await databases.decrementDocumentColumn(
    '<DATABASE_ID>',
    '<COLLECTION_ID>',
    '<DOCUMENT_ID>',
    'credits', // column
    50, // value
    0 // min (optional)
);

Follow best practices

Use for high-concurrency scenarios

Atomic numeric operations are most beneficial when multiple users or processes might update the same numeric field simultaneously.

Combine with regular updates

For complex updates that include both atomic operations and regular field changes, you'll need to use separate API calls:

// First, increment the likes atomically
const likeResult = await databases.incrementDocumentColumn(
    '<DATABASE_ID>',
    '<COLLECTION_ID>',
    '<DOCUMENT_ID>',
    'likes', // column
    1 // value
);

// Then, update other fields
const updateResult = await databases.updateDocument(
    '<DATABASE_ID>',
    '<COLLECTION_ID>',
    '<DOCUMENT_ID>',
    {
        lastLikedBy: userId,
        lastLikedAt: new Date().toISOString()
    }
);

Explore related features