{"id":18581903,"url":"https://github.com/coder/redjet","last_synced_at":"2025-08-31T20:13:19.891Z","repository":{"id":178735306,"uuid":"661432226","full_name":"coder/redjet","owner":"coder","description":"High-performance Redis library for Go","archived":false,"fork":false,"pushed_at":"2024-11-16T06:02:29.000Z","size":191,"stargazers_count":146,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-28T17:00:58.651Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-02T20:28:36.000Z","updated_at":"2025-08-25T16:53:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"0c15b17f-8c5a-40b9-8169-4b9ded0f9c0c","html_url":"https://github.com/coder/redjet","commit_stats":null,"previous_names":["ammario/redjet","coder/redjet"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/coder/redjet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fredjet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fredjet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fredjet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fredjet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coder","download_url":"https://codeload.github.com/coder/redjet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fredjet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273032934,"owners_count":25034067,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T00:08:15.153Z","updated_at":"2025-08-31T20:13:19.870Z","avatar_url":"https://github.com/coder.png","language":"Go","readme":"# redjet\n[![Go Reference](https://pkg.go.dev/badge/github.com/coder/redjet.svg)](https://pkg.go.dev/github.com/coder/redjet)\n![ci](https://github.com/coder/redjet/actions/workflows/ci.yaml/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/coder/redjet/badge.svg)](https://coveralls.io/github/coder/redjet)\n[![Go Report Card](https://goreportcard.com/badge/github.com/coder/redjet)](https://goreportcard.com/report/github.com/coder/redjet)\n\n\n\nredjet is a high-performance Go library for Redis. Its hallmark feature is\na low-allocation, streaming API. See the [benchmarks](#benchmarks) section for\nmore details.\n\nUnlike [redigo](https://github.com/gomodule/redigo) and [go-redis](https://github.com/redis/go-redis), redjet does not provide a function for every\nRedis command. Instead, it offers a generic interface that supports [all commands\nand options](https://redis.io/commands/). While this approach has less\ntype-safety, it provides forward compatibility with new Redis features.\n\nIn the aim of both performance and ease-of-use, redjet attempts to provide\nan API that closely resembles the protocol. For example, the `Command` method\nis really a Pipeline of size 1.\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**\n\n- [redjet](#redjet)\n  - [Basic Usage](#basic-usage)\n  - [Streaming](#streaming)\n  - [Pipelining](#pipelining)\n  - [PubSub](#pubsub)\n  - [JSON](#json)\n  - [Connection Pooling](#connection-pooling)\n  - [Benchmarks](#benchmarks)\n  - [Limitations](#limitations)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Basic Usage\n\nInstall:\n\n```bash\ngo get github.com/coder/redjet@latest\n```\n\nFor the most part, you can interact with Redis using a familiar interface:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n\n    \"github.com/coder/redjet\"\n)\n\nfunc main() {\n    client := redjet.New(\"localhost:6379\")\n    ctx := context.Background()\n\n    err := client.Command(ctx, \"SET\", \"foo\", \"bar\").Ok()\n    // check error\n\n    got, err := client.Command(ctx, \"GET\", \"foo\").Bytes()\n    // check error\n    // got == []byte(\"bar\")\n}\n```\n\n## Streaming\n\nTo minimize allocations, call `(*Pipeline).WriteTo` instead of `(*Pipeline).Bytes`.\n`WriteTo` streams the response directly to an `io.Writer` such as a file or HTTP response.\n\nFor example:\n\n```go\n_, err := client.Command(ctx, \"GET\", \"big-object\").WriteTo(os.Stdout)\n// check error\n```\n\nSimilarly, you can pass in a value that implements `redjet.LenReader` to\n`Command` to stream larger values into Redis. Unfortunately, the API\ncannot accept a regular `io.Reader` because bulk string messages in\nthe Redis protocol are length-prefixed.\n\nHere's an example of streaming a large file into Redis:\n\n```go\nbigFile, err := os.Open(\"bigfile.txt\")\n// check error\ndefer bigFile.Close()\n\nstat, err := bigFile.Stat()\n// check error\n\nerr = client.Command(\n    ctx, \"SET\", \"bigfile\",\n    redjet.NewLenReader(bigFile, stat.Size()),\n).Ok()\n// check error\n```\n\n\nIf you have no way of knowing the size of your blob in advance and still\nwant to avoid large allocations, you may chunk a stream into Redis using repeated [`APPEND`](https://redis.io/commands/append/) commands.\n\n## Pipelining\n\n`redjet` supports [pipelining](https://redis.io/docs/manual/pipelining/) via the `(*Client).Pipeline` method. This method accepts a `Pipeline`, potentially that of a previous, open command.\n\n```go\n// Set foo0, foo1, ..., foo99 to \"bar\", and confirm that each succeeded.\n//\n// This entire example only takes one round-trip to Redis!\nvar p *Pipeline\nfor i := 0; i \u003c 100; i++ {\n    p = client.Pipeline(p, \"SET\", fmt.Sprintf(\"foo%d\", i), \"bar\")\n}\n\nfor r.Next() {\n    if err := p.Ok(); err != nil {\n        log.Fatal(err)\n    }\n}\np.Close() // allow the underlying connection to be reused.\n```\n\n## PubSub\n\nredjet suports PubSub via the `NextSubMessage` method. For example:\n\n```go\n// Subscribe to a channel\nsub := client.Command(ctx, \"SUBSCRIBE\", \"my-channel\")\nsub.NextSubMessage() // ignore the first message, which is a confirmation of the subscription\n\n// Publish a message to the channel\nn, err := client.Command(ctx, \"PUBLISH\", \"my-channel\", \"hello world\").Int()\n// check error\n// n == 1, since there is one subscriber\n\n// Receive the message\nsub.NextSubMessage()\n// sub.Payload == \"hello world\"\n// sub.Channel == \"my-channel\"\n// sub.Type == \"message\"\n```\n\nNote that `NextSubMessage` will block until a message is received. To interrupt the subscription, cancel the context passed to `Command`.\n\nOnce a connection enters subscribe mode, the internal pool does not\nre-use it.\n\nIt is possible to subscribe to a channel in a performant, low-allocation way\nvia the public API. NextSubMessage is just a convenience method.\n\n## JSON\n\n`redjet` supports convenient JSON encoding and decoding via the `(*Pipeline).JSON` method. For example:\n\n```go\ntype Person struct {\n    Name string `json:\"name\"`\n    Age  int    `json:\"age\"`\n}\n\n// Set a person\n// Unknown argument types are automatically encoded to JSON.\nerr := client.Command(ctx, \"SET\", \"person\", Person{\n    Name: \"Alice\",\n    Age:  30,\n}).Ok()\n// check error\n\n// Get a person\nvar p Person\nclient.Command(ctx, \"GET\", \"person\").JSON(\u0026p)\n// check error\n\n// p == Person{Name: \"Alice\", Age: 30}\n```\n\n## Connection Pooling\n\nRedjet provides automatic connection pooling. Configuration knobs exist\nwithin the `Client` struct that may be changed before any Commands are\nissued.\n\nIf you want synchronous command execution over the same connection,\nuse the `Pipeline` method and consume the Pipeline after each call to `Pipeline`. Storing a long-lived `Pipeline`\noffers the same functionality as storing a long-lived connection.\n\n## Benchmarks\n\nOn a pure throughput basis, redjet will perform similarly to redigo and go-redis.\nBut, since redjet doesn't allocate memory for the entire response object, it\nconsumes far less resources when handling large responses.\n\nHere are some benchmarks (reproducible via `make gen-bench`) to illustrate:\n\n```\n.fullname: Get/1_B-10\n │   redjet    │               redigo               │           go-redis            │               rueidis                │\n │   sec/op    │   sec/op     vs base               │   sec/op     vs base          │    sec/op     vs base                │\n   908.2n ± 2%   962.4n ± 1%  +5.97% (p=0.000 n=10)   913.8n ± 3%  ~ (p=0.280 n=10)   1045.0n ± 1%  +15.06% (p=0.000 n=10)\n\n │    redjet     │                redigo                │            go-redis             │               rueidis                │\n │      B/s      │      B/s       vs base               │      B/s       vs base          │     B/s       vs base                │\n   1074.2Ki ± 2%   1015.6Ki ± 1%  -5.45% (p=0.000 n=10)   1069.3Ki ± 2%  ~ (p=0.413 n=10)   937.5Ki ± 1%  -12.73% (p=0.000 n=10)\n\n │  redjet   │            redigo            │           go-redis            │            rueidis            │\n │   B/op    │    B/op     vs base          │    B/op      vs base          │    B/op      vs base          │\n   0.00 ± 0%   41.00 ± 0%  ? (p=0.000 n=10)   275.50 ± 2%  ? (p=0.000 n=10)   249.00 ± 0%  ? (p=0.000 n=10)\n\n │   redjet   │            redigo            │           go-redis           │           rueidis            │\n │ allocs/op  │ allocs/op   vs base          │ allocs/op   vs base          │ allocs/op   vs base          │\n   0.000 ± 0%   3.000 ± 0%  ? (p=0.000 n=10)   4.000 ± 0%  ? (p=0.000 n=10)   2.000 ± 0%  ? (p=0.000 n=10)\n\n.fullname: Get/1.0_kB-10\n │   redjet    │               redigo                │              go-redis               │               rueidis               │\n │   sec/op    │   sec/op     vs base                │   sec/op     vs base                │   sec/op     vs base                │\n   1.302µ ± 2%   1.802µ ± 1%  +38.42% (p=0.000 n=10)   1.713µ ± 3%  +31.58% (p=0.000 n=10)   1.645µ ± 1%  +26.35% (p=0.000 n=10)\n\n │    redjet    │                redigo                │               go-redis               │               rueidis                │\n │     B/s      │     B/s       vs base                │     B/s       vs base                │     B/s       vs base                │\n   750.4Mi ± 2%   542.1Mi ± 1%  -27.76% (p=0.000 n=10)   570.3Mi ± 3%  -24.01% (p=0.000 n=10)   593.8Mi ± 1%  -20.87% (p=0.000 n=10)\n\n │    redjet    │             redigo             │            go-redis            │            rueidis             │\n │     B/op     │     B/op      vs base          │     B/op      vs base          │     B/op      vs base          │\n   0.000Ki ± 0%   1.039Ki ± 0%  ? (p=0.000 n=10)   1.392Ki ± 0%  ? (p=0.000 n=10)   1.248Ki ± 1%  ? (p=0.000 n=10)\n\n │   redjet   │            redigo            │           go-redis           │           rueidis            │\n │ allocs/op  │ allocs/op   vs base          │ allocs/op   vs base          │ allocs/op   vs base          │\n   0.000 ± 0%   3.000 ± 0%  ? (p=0.000 n=10)   4.000 ± 0%  ? (p=0.000 n=10)   2.000 ± 0%  ? (p=0.000 n=10)\n\n.fullname: Get/1.0_MB-10\n │   redjet    │            redigo             │              go-redis               │            rueidis            │\n │   sec/op    │   sec/op     vs base          │   sec/op     vs base                │   sec/op     vs base          │\n   472.5µ ± 7%   477.3µ ± 2%  ~ (p=0.190 n=10)   536.8µ ± 6%  +13.61% (p=0.000 n=10)   475.3µ ± 6%  ~ (p=0.684 n=10)\n\n │    redjet    │             redigo             │               go-redis               │            rueidis             │\n │     B/s      │     B/s       vs base          │     B/s       vs base                │     B/s       vs base          │\n   2.067Gi ± 8%   2.046Gi ± 2%  ~ (p=0.190 n=10)   1.819Gi ± 6%  -11.98% (p=0.000 n=10)   2.055Gi ± 6%  ~ (p=0.684 n=10)\n\n │   redjet    │                    redigo                    │                   go-redis                   │                   rueidis                    │\n │    B/op     │      B/op        vs base                     │      B/op        vs base                     │      B/op        vs base                     │\n   51.00 ± 12%   1047849.50 ± 0%  +2054506.86% (p=0.000 n=10)   1057005.00 ± 0%  +2072458.82% (p=0.000 n=10)   1048808.50 ± 0%  +2056387.25% (p=0.000 n=10)\n\n │   redjet   │               redigo                │              go-redis               │               rueidis               │\n │ allocs/op  │ allocs/op   vs base                 │ allocs/op   vs base                 │ allocs/op   vs base                 │\n   1.000 ± 0%   3.000 ± 0%  +200.00% (p=0.000 n=10)   4.000 ± 0%  +300.00% (p=0.000 n=10)   2.000 ± 0%  +100.00% (p=0.000 n=10)\n\n```\n\n## Limitations\n\n- redjet does not have convenient support for client side caching. But, the redjet API\n  is flexible enough that a client could implement it themselves by following the instructions [here](https://redis.io/docs/manual/client-side-caching/#two-connections-mode).\n- RESP3 is not supported. Practically, this means that connections aren't\n  multiplexed, and other Redis libraries may perform better in high-concurrency\n  scenarios.\n- Certain features have not been tested but may still work:\n  - Redis Streams\n  - Monitor","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoder%2Fredjet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoder%2Fredjet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoder%2Fredjet/lists"}