> For the complete documentation index, see [llms.txt](https://docs.hardpoint.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hardpoint.dev/guides/invar/usage.md).

# Usage

Interacting with Invar as a client

This page assumes you already know Redis. Rather than re-documenting commands that work exactly as you'd expect, it covers where talking to Invar differs from talking to real Redis. For the exhaustive, per-command status, see the [Redis command support](broken://pages/10a096c1966394235460299e3d60079a0d1bfada) appendix.

## Connecting

Invar speaks RESP2. `HELLO` requests for RESP3 are refused with a `NOPROTO` error rather than silently downgraded. Most client libraries negotiate this automatically and just work; if yours has a setting that forces RESP3, switch it off.

There's no `AUTH` and no ACL support — connection-level authentication is explicitly out of scope for Invar itself. Treat this the way you'd treat any unauthenticated service: put it behind a VPC, security group, or sidecar, not on the open internet. If you need per-tenant credentials or access control, that's what [Hardpoint's managed offerings](https://hardpoint.dev/) are for.

## Document commands (JSON.\*)

This is the part that isn't "just Redis." Invar supports RedisJSON-style document commands on top of the same wire protocol:

```bash
redis-cli JSON.SET user:1 $ '{"name": "Ada", "roles": ["admin", "beta"], "logins": 0}'
redis-cli JSON.GET user:1 $.roles
# ["admin","beta"]
redis-cli JSON.NUMINCRBY user:1 $.logins 1
redis-cli JSON.ARRAPPEND user:1 $.roles '"trial"'
```

Array and object manipulation, string ops (`JSON.STRAPPEND`, `JSON.STRLEN`), and numeric increments are all in. A few of the newer or more obscure ones — `JSON.MERGE`, `JSON.MSET`, `JSON.TOGGLE`, `JSON.FORGET` — aren't implemented yet; check the appendix if you depend on one of these.

## Bloom filters (BF.\*)

Core RedisBloom-style filter commands work: `BF.ADD`, `BF.MADD`, `BF.EXISTS`, `BF.MEXISTS`, `BF.INSERT`, `BF.RESERVE`, `BF.INFO`. Filter export/import (`BF.SCANDUMP`, `BF.LOADCHUNK`) and `BF.CARD` aren't there yet — if your usage depends on shipping filters between instances, hold off for now.

## Transactions

`MULTI`, `EXEC`, and `DISCARD` behave as you'd expect.

{% hint style="warning" %}
**`WATCH` and `UNWATCH` aren't implemented yet.** Optimistic-locking patterns — watch a key, queue a transaction, retry on conflict — don't translate to Invar today. If your application leans on that pattern for compare-and-swap–style updates, you'll need another approach for now, or an application-level retry that doesn't rely on `WATCH`.
{% endhint %}

## Scripting (EVAL/EVALSHA)

Invar runs Lua scripts through [Piccolo](https://github.com/kyren/piccolo), a Lua interpreter written in Rust — not the reference Lua/LuaJIT that Redis itself uses. It covers the core stdlib (`base`, `coroutine`, `math`, `string`, `table`) plus `tonumber`, `unpack`, `table.insert`/`remove`/`sort`/`concat`, `cmsgpack.unpack`, and `cjson.encode`, and exposes `redis.call()` / `redis.pcall()` as usual.

Practically: straightforward scripts that touch keys and do basic Lua port over fine. Scripts that reach for stdlib functions outside that list, or depend on reference-Lua-specific behavior, may need adjustment — worth testing scripts against Invar directly rather than assuming compatibility.

## Pub/Sub

`PUBLISH`/`SUBSCRIBE`/`PSUBSCRIBE` and friends (including the `SSUBSCRIBE`/`SPUBLISH` sharded aliases) work, but — same as Redis — Pub/Sub messages are **not persisted and not covered by transactional guarantees**. Fine for cache invalidation or best-effort signaling; not the right tool for anything you need to survive a restart.

## Streams

The core stream operations work: `XADD` (with `NOMKSTREAM`, `MAXLEN`, `MINID` trimming), `XREAD`, `XRANGE`/`XREVRANGE`, `XTRIM`, `XLEN`, `XDEL`, `XSETID`, `XINFO STREAM`.

{% hint style="warning" %}
**Consumer groups are not implemented.** `XGROUP`, `XREADGROUP`, `XACK`, `XCLAIM`, `XAUTOCLAIM`, `XPENDING`, and the related `XINFO` subcommands aren't there. If your usage depends on consumer-group semantics rather than plain stream reads, that's currently a gap.
{% endhint %}

## Expiry and key commands

`EXPIRE`, `PEXPIRE`, `PERSIST`, `TTL`, and `PTTL` all work normally. The absolute-time variants — `EXPIREAT`, `PEXPIREAT`, `EXPIRETIME`, `PEXPIRETIME` — aren't implemented yet, so set TTLs relatively rather than by absolute timestamp for now.

`KEYS` isn't implemented; use `SCAN` instead, which supports `MATCH`, `COUNT`, and `TYPE`. This is a case where Invar just enforces what's already best practice in Redis — `KEYS` blocks the whole server and is generally discouraged in production anyway.

{% hint style="warning" %}
**`DBSIZE` runs in O(n) time**, not O(1) like Redis. Don't put it on a hot path or a frequent health check.
{% endhint %}

## What's intentionally out of scope

A few command groups aren't gaps so much as deliberate non-goals:

* **Cluster management** (`CLUSTER *`, `REPLICAOF`/`SLAVEOF`, etc.): doesn't map onto Invar's single-writer, single-process model. `PSYNC`, `SYNC`, and `WAIT` exist as no-ops for client compatibility but don't do anything.
* **Geospatial commands:** no current plans; large maintenance surface for a use case that hasn't come up.
* **ACL / AUTH / RBAC:** out of scope for Invar itself, as noted above.
* **Server introspection** (`CONFIG GET`/`SET`, `MEMORY *`, `LATENCY *`, `SLOWLOG *`, `MONITOR`, `DEBUG`): not implemented. `INFO`, `CLIENT INFO`/`LIST`, and `TIME` are, and cover most of what you'd actually check at runtime. Where command coverage exists, the goal is to maximise compatibility with common clients (e.g. [ioredis](https://ioredis.com)), rather than to maintain functional parity with upstream Redis for each server command.

For the full picture, including anything not mentioned here, see the [Redis command support](broken://pages/10a096c1966394235460299e3d60079a0d1bfada) appendix.
