| 1 | --- |
| 2 | title: Redis |
| 3 | description: Managed Upstash Redis. Bind Fly.ReadRedis / WriteRedis / ReadWriteRedis on a Service. |
| 4 | --- |
| 5 | |
| 6 | [`Fly.Redis`](/providers/fly/redis) is managed Upstash Redis in a |
| 7 | Fly org. Bind [`ReadWriteRedis`](/providers/fly/readwriteredis) on a |
| 8 | [Service](/fly/compute/services). The runtime client reads the bound |
| 9 | resource's redacted `url` Output. Alchemy also attaches the add-on and |
| 10 | writes `REDIS_URL` as an App secret for compatibility. Redis is not |
| 11 | reachable from CI — drive it over HTTP. |
| 12 | |
| 13 | ## Create Redis |
| 14 | |
| 15 | Alchemy generates a unique name unless you pass one. Default |
| 16 | [region](/fly/compute/regions) is `iad`. Default plan is the |
| 17 | cheapest `addOnPlans` row (free or pay-as-you-go). |
| 18 | |
| 19 | ```typescript |
| 20 | const cache = yield* Fly.Redis("Cache"); |
| 21 | ``` |
| 22 | |
| 23 | :::note |
| 24 | Prefer omitting `name` in tests and CI so names stay unique and |
| 25 | reclaimable. |
| 26 | ::: |
| 27 | |
| 28 | ## A stable name |
| 29 | |
| 30 | Pass `name` when you want a stable Upstash database name. |
| 31 | |
| 32 | ```typescript |
| 33 | const cache = yield* Fly.Redis("Cache", { |
| 34 | name: "my-cache", |
| 35 | primaryRegion: "iad", |
| 36 | }); |
| 37 | ``` |
| 38 | |
| 39 | :::caution[Changing `name` replaces Redis] |
| 40 | Fly cannot rename an add-on. Alchemy deletes the old database first, |
| 41 | then creates the new one. |
| 42 | ::: |
| 43 | |
| 44 | :::caution[Changing `primaryRegion` replaces Redis] |
| 45 | The primary region is immutable. The old database is deleted first |
| 46 | because the name cannot exist twice. |
| 47 | ::: |
| 48 | |
| 49 | ## Bind from a Service |
| 50 | |
| 51 | Yield `Fly.ReadWriteRedis` (or `ReadRedis` / `WriteRedis`) in |
| 52 | the Service's constructor. Provide the matching `*Http` layer. |
| 53 | |
| 54 | ```typescript |
| 55 | import * as HttpServerResponse from "effect/http/HttpServerResponse"; |
| 56 | |
| 57 | const Cache = Fly.Redis("Cache"); |
| 58 | |
| 59 | export default class Api extends Fly.Service<Api>()( |
| 60 | "Api", |
| 61 | { main: import.meta.url, port: 3000 }, |
| 62 | Effect.gen(function* () { |
| 63 | const cache = yield* Fly.ReadWriteRedis(Cache); |
| 64 | return { |
| 65 | fetch: Effect.gen(function* () { |
| 66 | yield* cache.set("marker", "hello"); |
| 67 | const value = yield* cache.get("marker"); |
| 68 | return HttpServerResponse.json({ value }); |
| 69 | }), |
| 70 | }; |
| 71 | }).pipe(Effect.provide(Fly.ReadWriteRedisHttp)), |
| 72 | ) {} |
| 73 | ``` |
| 74 | |
| 75 | ## Eviction |
| 76 | |
| 77 | Enable eviction for cache workloads. Updated in place. |
| 78 | |
| 79 | ```typescript |
| 80 | const cache = yield* Fly.Redis("Cache", { |
| 81 | eviction: true, |
| 82 | }); |
| 83 | ``` |
| 84 | |
| 85 | ## Read replicas |
| 86 | |
| 87 | `readRegions` are extra replica regions. Updated in place. They |
| 88 | must not include the primary region. |
| 89 | |
| 90 | ```typescript |
| 91 | const cache = yield* Fly.Redis("Cache", { |
| 92 | primaryRegion: "iad", |
| 93 | readRegions: ["sjc"], |
| 94 | }); |
| 95 | ``` |
| 96 | |
| 97 | ## Plan |
| 98 | |
| 99 | Omit `plan` for the cheapest listed plan. Pass a plan id or display |
| 100 | name to pin one. Fixed plans are billed. |
| 101 | |
| 102 | ```typescript |
| 103 | const cache = yield* Fly.Redis("Cache", { |
| 104 | plan: "Pay-as-you-go", |
| 105 | }); |
| 106 | ``` |
| 107 | |
| 108 | :::caution[Fixed plans are billed] |
| 109 | Fixed plans are billed monthly. Prefer omitting `plan` unless you |
| 110 | need a specific size. |
| 111 | ::: |
| 112 | |
| 113 | ## Where next |
| 114 | |
| 115 | [Regions](/fly/compute/regions) lists codes. Default primary is |
| 116 | `iad`. |
| 117 | [Services](/fly/compute/services) is the Machine that binds |
| 118 | `ReadWriteRedis`. |
| 119 | The [`Redis` reference](/providers/fly/redis) lists every prop. |