{
  "schema_version": 2,
  "id": "commands/setnx",
  "title": "SETNX",
  "url": "https://redis.io/docs/latest/commands/setnx/",
  "summary": "Set the string value of a key only when the key doesn't exist.",
  "since": "1.0.0",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-09-18T16:45:12+01:00",
  "page_type": "content",
  "content_hash": "2a5dfc272b6fd29fe9ed7fd08798f39b0001253e4905c073be456e7bcec0e9f8",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Set `key` to hold string `value` if `key` does not exist.\nIn that case, it is equal to [`SET`](https://redis.io/docs/latest/commands/set).\nWhen `key` already holds a value, no operation is performed.\n`SETNX` is short for \"**SET** if **N**ot e**X**ists\"."
    },
    {
      "id": "required-arguments",
      "title": "Required arguments",
      "role": "content",
      "text": "<details open><summary><code>key</code></summary>\n\nThe name of the key.\n\n</details>\n\n<details open><summary><code>value</code></summary>\n\nThe value to set, only if the key does not already exist.\n\n</details>"
    },
    {
      "id": "examples",
      "title": "Examples",
      "role": "example",
      "text": "redis> SETNX mykey \"Hello\"\n(integer) 1\nredis> SETNX mykey \"World\"\n(integer) 0\nredis> GET mykey\n\"Hello\""
    },
    {
      "id": "details",
      "title": "Details",
      "role": "content",
      "text": ""
    },
    {
      "id": "design-pattern-locking-with-setnx",
      "title": "Design pattern: locking with `SETNX`",
      "role": "content",
      "text": "**Please note that:**\n\n1. The following pattern is discouraged in favor of [the Redlock algorithm](https://redis.io/docs/latest/develop/clients/patterns/distributed-locks) which is only a bit more complex to implement, but offers better guarantees and is fault tolerant.\n2. We document the old pattern anyway because certain existing implementations link to this page as a reference. Moreover it is an interesting example of how Redis commands can be used in order to mount programming primitives.\n3. Anyway even assuming a single-instance locking primitive, starting with 2.6.12 it is possible to create a much simpler locking primitive, equivalent to the one discussed here, using the [`SET`](https://redis.io/docs/latest/commands/set) command to acquire the lock, and a simple Lua script to release the lock. The pattern is documented in the [`SET`](https://redis.io/docs/latest/commands/set) command page.\n\nThat said, `SETNX` can be used, and was historically used, as a locking primitive. For example, to acquire the lock of the key `foo`, the client could try the\nfollowing:\n\n[code example]\n\nIf `SETNX` returns `1` the client acquired the lock, setting the `lock.foo` key\nto the Unix time at which the lock should no longer be considered valid.\nThe client will later use `DEL lock.foo` in order to release the lock.\n\nIf `SETNX` returns `0` the key is already locked by some other client.\nWe can either return to the caller if it's a non blocking lock, or enter a loop\nretrying to hold the lock until we succeed or some kind of timeout expires.\n\n#### Handling deadlocks\n\nIn the above locking algorithm there is a problem: what happens if a client\nfails, crashes, or is otherwise not able to release the lock?\nIt's possible to detect this condition because the lock key contains a UNIX\ntimestamp.\nIf such a timestamp is equal to the current Unix time the lock is no longer\nvalid.\n\nWhen this happens we can't just call [`DEL`](https://redis.io/docs/latest/commands/del) against the key to remove the lock\nand then try to issue a `SETNX`, as there is a race condition here, when\nmultiple clients detected an expired lock and are trying to release it.\n\n* C1 and C2 read `lock.foo` to check the timestamp, because they both received\n  `0` after executing `SETNX`, as the lock is still held by C3 that crashed\n  after holding the lock.\n* C1 sends `DEL lock.foo`\n* C1 sends `SETNX lock.foo` and it succeeds\n* C2 sends `DEL lock.foo`\n* C2 sends `SETNX lock.foo` and it succeeds\n* **ERROR**: both C1 and C2 acquired the lock because of the race condition.\n\nFortunately, it's possible to avoid this issue using the following algorithm.\nLet's see how C4, our sane client, uses the good algorithm:\n\n*   C4 sends `SETNX lock.foo` in order to acquire the lock\n\n*   The crashed client C3 still holds it, so Redis will reply with `0` to C4.\n\n*   C4 sends `GET lock.foo` to check if the lock expired.\n    If it is not, it will sleep for some time and retry from the start.\n\n*   Instead, if the lock is expired because the Unix time at `lock.foo` is older\n    than the current Unix time, C4 tries to perform:\n\n    [code example]\n\n*   Because of the [`GETSET`](https://redis.io/docs/latest/commands/getset) semantic, C4 can check if the old value stored at\n    `key` is still an expired timestamp.\n    If it is, the lock was acquired.\n\n*   If another client, for instance C5, was faster than C4 and acquired the lock\n    with the [`GETSET`](https://redis.io/docs/latest/commands/getset) operation, the C4 [`GETSET`](https://redis.io/docs/latest/commands/getset) operation will return a non\n    expired timestamp.\n    C4 will simply restart from the first step.\n    Note that even if C4 set the key a bit a few seconds in the future this is\n    not a problem.\n\nIn order to make this locking algorithm more robust, a\nclient holding a lock should always check the timeout didn't expire before\nunlocking the key with [`DEL`](https://redis.io/docs/latest/commands/del) because client failures can be complex, not just\ncrashing but also blocking a lot of time against some operations and trying\nto issue [`DEL`](https://redis.io/docs/latest/commands/del) after a lot of time (when the LOCK is already held by another\nclient)."
    },
    {
      "id": "redis-software-and-redis-cloud-compatibility",
      "title": "Redis Software and Redis Cloud compatibility",
      "role": "content",
      "text": "| Redis<br />Software | Redis<br />Cloud | <span style=\"min-width: 9em; display: table-cell\">Notes</span> |\n|:----------------------|:-----------------|:------|\n| <span title=\"Supported\">&#x2705; Standard</span><br /><span title=\"Supported\"><nobr>&#x2705; Active-Active</nobr></span> | <span title=\"Supported\">&#x2705; Standard</span><br /><span title=\"Supported\"><nobr>&#x2705; Active-Active</nobr></span> |  |"
    },
    {
      "id": "return-information",
      "title": "Return information",
      "role": "returns",
      "text": "**RESP2:**\n\nOne of the following:\n* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the key was not set.\n* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the key was set.\n\n**RESP3:**\n\nOne of the following:\n* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the key was not set.\n* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the key was set."
    }
  ],
  "examples": [
    {
      "id": "design-pattern-locking-with-setnx-ex0",
      "language": "plaintext",
      "code": "SETNX lock.foo <current Unix time + lock timeout + 1>",
      "section_id": "design-pattern-locking-with-setnx"
    },
    {
      "id": "design-pattern-locking-with-setnx-ex1",
      "language": "plaintext",
      "code": "GETSET lock.foo <current Unix timestamp + lock timeout + 1>",
      "section_id": "design-pattern-locking-with-setnx"
    }
  ]
}
