hiredis and the limits of a protocol-only C client for Redis
Minimalistic C client for Redis >= 1.2
At a glance
- What is it?
- hiredis is the C client that speaks only the binary-safe Redis protocol and stops there: a three-call synchronous API, a reusable reply parser, and no command bindings, and no managed reply memory.
- Who is it for?
- Hiredis fits one specific slot: a C program that already talks Redis at the protocol level and wants reply parsing without a binding generator or a third-party client with its own dependency tree. The three-call synchronous API, the reusable stream parser and a BSD-3-Clause license make that case cleanly.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 30 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- redis/hiredis6,693 ★ · +5
| Repository | 2026-09-23 | 2026-11-13 |
|---|---|---|
| redis/hiredis | 6.7k | 6.7k |
5 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
A printf-alike API over the binary-safe protocol only
Hiredis is a C client library for Redis that deliberately stops at the protocol. It adds minimal support for the wire format and layers a high level printf-alike API on top, so you format commands as format strings rather than through per-command bindings. There are no explicit bindings for every Redis command, and that restraint is the design: the surface stays small and one call shape covers the whole command set.
The narrowness has a consequence worth stating first. Hiredis speaks only the binary-safe Redis protocol, so it works with any Redis server at version 1.2.0 or newer.
Three APIs ship in the library: a synchronous API, an asynchronous API, and a reply parsing API. The reply parser is decoupled from the I/O layer and written as a stream parser, which is what lets a language binding lift it out and reuse it for reply handling without inheriting the socket code. The synchronous entry points are three functions: `redisConnect`, `redisCommand` and `freeReplyObject`.
poll(2) retries after v1.2.0 replaced a hard connection failure
Connecting changed in a way that only shows up on hosts that send signals. After v1.2.0, hiredis invokes `poll(2)` differently while waiting for a connection to complete, and now retries the call when a signal interrupts it. The retry loop ends only when the connection succeeds or fails, or when the overall connection timeout is reached.
Before that change, a `poll(2)` call interrupted by a signal failed the connection outright. The context came back with `c->err` set to `REDIS_ERR_IO` and `c->errstr` set to `poll(2): Interrupted system call`. A caller treating any non-zero `err` as fatal would surface a spurious connection failure when a timer signal crossed the wait.
The new behaviour trades that early return for patience: a stuck connection now consumes the whole connection timeout instead of failing on the first interruption. The README labels this section PRERELEASE, and what it describes is written against the master branch rather than a tagged release, so read it as a statement about where the code is heading.
connect_timeout and command_timeout: what the 1.0.0 rename cost callers
Version 1.0.0 was the first stable release, and it broke source compatibility on purpose to make the exposed API more uniform. Three changes matter to an existing caller.
`redisOptions.timeout` was renamed to `redisOptions.connect_timeout`, and a second field, `redisOptions.command_timeout`, was added next to it. Code that still assigns `timeout` no longer says what it thinks it says, and one knob has become two. Splitting connect time from command time is a real gain on a slow server, but every existing call site has to be revisited.
The `redisContext` struct gained two members, `free_privdata` and `privctx`, so anything that lays the struct out itself has two more fields to account for.
`redisReplyObjectFunctions.createArray` now takes a `size_t` for its length parameter instead of an `int`. That is the change that breaks code most quietly, because the mismatch only surfaces where the two widths differ.
The release also bundles an updated `sds` library, the string helper Redis itself uses, to keep the two copies in sync. `CHANGELOG.md` holds the full list of code changes.
The reply parser is yours to lift, and its length limits moved
The reply parser is the piece other projects lift, and the bounds it enforces are the piece most often misused. Since the 0.14.x line, a bulk or multi-bulk length below -1 or above `LLONG_MAX` is treated as a protocol error instead of being accepted, which is consistent with the RESP specification. On 32-bit platforms the upper bound drops to `SIZE_MAX`.
The same change moved `redisReply.len` to `size_t`, because it denotes the size of a string. User code that compares it against an `int` now needs a cast, and code that already cast can drop the cast. It is a mechanical fix, but it runs through every call site that touches a reply.
RESP3 doubles are the other trap. As of 1.1.0, hiredis can return `nan` in a `REDIS_REPLY_DOUBLE` in addition to `inf` and `-inf`, and applications that deal with RESP3 doubles are told to account for it. Code written against RESP2 had two special values to compare against; a third now arrives in the same reply type with no branch of its own.
Building libhiredis and the redis-server its test suite expects
Hiredis builds from source with a plain Makefile and a bare invocation:
makeThe object list is fixed and short: `alloc.o`, `net.o`, `hiredis.o`, `sds.o`, `async.o`, `read.o` and `sockcompat.o`, assembled into `libhiredis` with pkg-config output named `hiredis.pc`. Six example binaries are built alongside it, covering libevent, libev, glib, push and poll integrations, and the test binary is `hiredis-test`.
Install locations come from variables declared with `?=`. `PREFIX` defaults to `/usr/local`, headers land in `include/hiredis`, the library in `lib`, the pkg-config file in `pkgconfig`. `CFLAGS` and `LDFLAGS` are left alone on purpose, with `HIREDIS_CFLAGS` and `HIREDIS_LDFLAGS` reserved for outside flags, and optimisation defaults to `-O3`.
The test binary expects a redis-server on port 56379 rather than 6379, bound to 127.0.0.1 with a unix socket at `/tmp/hiredis-test-redis.sock`. The Makefile exports the config it feeds that server as `REDIS_TEST_CONFIG`:
daemonize yes
pidfile /tmp/hiredis-test-redis.pid
port 56379
bind 127.0.0.1
unixsocket /tmp/hiredis-test-redis.sockA first real use is three calls. Connect, check the error field, send a command, then release the reply:
redisContext *c = redisConnect("127.0.0.1", 6379);
if (c == NULL || c->err) {
if (c) {
printf("Error: %s\n", c->errstr);
// handle error
} else {
printf("Can't allocate redis context\n");
}
}That error check is not decoration. `redisConnect` hands back a context even when the socket fails, so a caller that skips the check will issue commands on a dead connection.
Endpoint and flag control goes through `redisConnectWithOptions`, which takes a `redisOptions` struct that helper macros populate:
redisOptions opt = {0};
/* One can set the endpoint with one of our helper macros */
if (tcp) {
REDIS_OPTIONS_SET_TCP(&opt, "localhost", 6379);
} else {
REDIS_OPTIONS_SET_UNIX(&opt, "/tmp/redis.sock");
}
/* And privdata can be specified with another helper */
REDIS_OPTIONS_SET_PRIVDATA(&opt, myPrivData, myPrivDataDtor);
/* Finally various options may be set via the `options` member, as described below */
opt->options |= REDIS_OPT_PREFER_IPV4;The flags themselves are a short table. `REDIS_OPT_NONBLOCK` asks for a non-blocking connection, `REDIS_OPT_REUSEADDR` sets the socket option of that name.
The synchronous API stops at three calls, and memory stays with you
This is where hiredis stops helping. The synchronous surface is three functions, and everything around them belongs to the caller.
There is no command typing. `redisCommand` takes a printf-alike format string and returns a `void *` reply that the caller inspects. Command names and argument types are string literals in your code and nothing checks them.
Reply memory is manual. `freeReplyObject` releases a reply, and every reply you receive is one you must release.
Recovery is a single call. `redisReconnect` restores the connection using the same endpoint and options as the given context.
The README tracks master while the tags run to v1.4.1
The documentation you are reading is not the documentation for a release. The README header states that it reflects the latest changes in the master branch and points readers to the v1.0.0 tree for the latest release's README and documentation. The release list meanwhile carries v1.5.0 (2026-10-15), v1.2.1 and v1.1.1, the last two published on 2026-08-06 within about a minute of each other.
Two version facts matter if you link against the library. v1.0.1 is not a usable upgrade step: it erroneously bumped SONAME, which is why the upgrade notes skip it entirely. Version 1.0.2 is simply 1.0.0 plus a fix for CVE-2021-32765 and is otherwise identical to 1.0.0.
The ABI version lives in the header, not in the build file. The Makefile reads `HIREDIS_MAJOR`, `HIREDIS_MINOR`, `HIREDIS_PATCH` and `HIREDIS_SONAME` out of `hiredis.h` with `grep` and `awk`, so whoever packages this library has to agree with whatever is declared there. An API and ABI history timeline is linked from the README header for anyone who needs more.
The license is BSD-3-Clause, with the terms in `COPYING`. TLS support has its own files in `ssl.c` and `hiredis_ssl.h`, separate pkg-config templates for `hiredis` and `hiredis_ssl`, CMake config templates for both, and an SSL example under `examples/`.
Editorial conclusion
Hiredis fits one specific slot: a C program that already talks Redis at the protocol level and wants reply parsing without a binding generator or a third-party client with its own dependency tree. The three-call synchronous API, the reusable stream parser and a BSD-3-Clause license make that case cleanly. It does not fit a team that wants typed commands or managed reply memory. Before adopting it, check three things against your own build: whether the SONAME declared in hiredis.h matches what your distribution expects, whether your RESP3 double handling covers nan as of 1.1.0, and whether the master-branch README describes behaviour that actually shipped in the tag you pin.
Frequently asked questions
What is hiredis?
It is a minimalistic C client library for the Redis database. It adds minimal support for the protocol, exposes a high level printf-alike API instead of bindings for every command, and ships a reply parser that is decoupled from the I/O layer so other bindings can reuse it.
How do I install hiredis?
From source. The repository ships a Makefile and a CMakeLists.txt. The Makefile builds libhiredis with pkg-config output named hiredis.pc, and its install paths come from variables that default to PREFIX=/usr/local, headers under include/hiredis, the library under lib, and the pkgconfig directory for the config file.
How do I use hiredis from a C program?
Create a context with redisConnect, check the context's err field before you use it, send commands through redisCommand with a printf-alike format string, and release every reply with freeReplyObject. For endpoint and flag control, redisConnectWithOptions takes a redisOptions struct.
What is redis/hiredis on GitHub?
The C client library for Redis published by the redis organisation, written in C on the master branch under a BSD-3-Clause license. Its last push was on 2026-10-15, and the published releases include v1.5.0, v1.2.1 and v1.1.1.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/redis-hiredis)Star history chart for your README
[](https://hysenlabs.com/projects/redis-hiredis)Was this useful?