Lodash _.uniqueId: Prefix Generation Guarantees

The _.uniqueId method in Lodash is a lightweight utility designed to generate unique identifiers within a running JavaScript process. This article breaks down the guarantees _.uniqueId provides when generating IDs with custom prefixes, details how its internal counter functions, and highlights the scope and architectural boundaries developers must consider when relying on it.

The Core Mechanism of _.uniqueId

Under the hood, Lodash implements _.uniqueId with a simple global counter and basic string concatenation. When invoked, it increments an internal integer variable and appends it to the user-supplied prefix string:

let idCounter = 0;

function uniqueId(prefix = '') {
  const id = ++idCounter;
  return `${prefix}${id}`;
}

If no prefix is provided, it simply returns the stringified counter value.

Guarantees Provided for Prefix Generation

When utilizing _.uniqueId with a prefix, Lodash offers specific behaviors you can reliably expect:

1. In-Memory Session Uniqueness

Every call to _.uniqueId is guaranteed to return a unique string within the lifecycle of the current JavaScript runtime environment. If you supply a prefix like 'user_', the generated ID will not collide with another 'user_' ID generated during the same execution session.

2. Strict Sequential Monotonicity

The generated suffixes are strictly monotonic integers starting from 1 and increasing by 1 with each call. For a single prefix executed in isolation, outputs follow a predictable sequence: prefix_1, prefix_2, prefix_3.

3. Reliable Type Coercion

Regardless of the prefix type passed (strings, numbers, or objects), Lodash safely casts the prefix to a string. Calling _.uniqueId('item_') produces 'item_1', and calling _.uniqueId(42) produces '421'.


Important Limitations and Non-Guarantees

Understanding what _.uniqueId does not provide is critical for avoiding bugs in distributed or persistent architectures.

Independent Prefix Counters Are Not Guaranteed

Lodash uses a single, shared counter across all invocations of _.uniqueId, regardless of the prefix provided. Counters are not partitioned per prefix.

_.uniqueId('button_'); // "button_1"
_.uniqueId('input_');  // "input_2"
_.uniqueId('button_'); // "button_3"

Notice that the second button_ ID is button_3, not button_2.

No Cross-Process or Distributed Uniqueness

Because the counter lives solely in module-level memory:

_.uniqueId is not a replacement for UUIDs (v4) or distributed IDs (like Snowflake or ULID) when uniqueness across networks, databases, or processes is required.

No Cryptographic Security or Unpredictability

The incrementing nature of _.uniqueId makes IDs completely predictable. It should never be used for security tokens, session identifiers, password reset links, or any context where an attacker could guess sequential values.

Integer Bounds

In standard JavaScript runtimes, numbers are represented as IEEE 754 double-precision floats. While Lodash counters can safely increment up to Number.MAX_SAFE_INTEGER (9,007,199,254,740,991) before losing precision, long-lived Node.js processes calling the method billions of times could theoretically exceed safe bounds, though this is rare in practice.


Ideal Use Cases

Given these properties, _.uniqueId with a prefix is best suited for ephemeral, client-side identifiers such as: