{
  "schema_version": 2,
  "id": "develop/clients/go/connect",
  "title": "Connect to the server",
  "url": "https://redis.io/docs/latest/develop/clients/go/connect/",
  "summary": "Connect your Go application to a Redis database",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-10-12T14:48:04+01:00",
  "page_type": "content",
  "content_hash": "67a97225721b203ca555812fbcdd916db8be41c3a8c03a7e58dca5d119a9277f",
  "sections": [
    {
      "id": "basic-connection",
      "title": "Basic connection",
      "role": "overview",
      "text": "The following example shows the simplest way to connect to a Redis server:\n\n[code example]\n\nYou can also connect using a connection URL:\n\n[code example]\n\n> [!NOTE]\n> go-redis supports [connection URLs](https://redis.io/docs/latest/develop/clients/connection-urls#go-redis-go) through `redis.ParseURL()`.\n> A URL can set the host, port, credentials, database, and whether to use TLS,\n> so you can use one instead of passing those options separately.\n\nAfter connecting, you can test the connection by  storing and retrieving\na simple [string](https://redis.io/docs/latest/develop/data-types/strings):\n\n[code example]"
    },
    {
      "id": "connect-to-a-redis-cluster",
      "title": "Connect to a Redis cluster",
      "role": "content",
      "text": "To connect to a Redis cluster, use `NewClusterClient()`. You can specify\none or more cluster endpoints with the `Addrs` option:\n\n[code example]"
    },
    {
      "id": "connect-to-redis-sentinel",
      "title": "Connect to Redis Sentinel",
      "role": "content",
      "text": "To connect through [Redis Sentinel](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel),\nuse `NewFailoverClient()`. Set `MasterName` to the name of the primary that the Sentinels\nmonitor, and list one or more Sentinels in `SentinelAddrs`. The client asks the Sentinels\nfor the current primary and switches to the new one after a failover.\n\n[code example]\n\nThe Sentinels and the data nodes have separate credentials. Set `SentinelPassword` for the\nSentinels, and `Username` and `Password` for the primary and replicas:\n\n[code example]\n\nTo send commands to a replica, set `ReplicaOnly`. The client sends every command to a\nrandom replica, including writes, which fail, so use this option only for a client that\nreads:\n\n[code example]"
    },
    {
      "id": "connect-to-your-production-redis-with-tls",
      "title": "Connect to your production Redis with TLS",
      "role": "content",
      "text": "When you deploy your application, use TLS and follow the\n[Redis security](https://redis.io/docs/latest/operate/oss_and_stack/management/security) guidelines.\n\nEstablish a secure connection with your Redis database:\n\n[code example]"
    },
    {
      "id": "connect-using-smart-client-handoffs-sch",
      "title": "Connect using Smart client handoffs (SCH)",
      "role": "content",
      "text": "*Smart client handoffs (SCH)* is a feature of Redis Cloud and\nRedis Software servers that lets them actively notify clients\nabout planned server maintenance shortly before it happens. This\nlets a client take action to avoid disruptions in service.\nSee [Smart client handoffs](https://redis.io/docs/latest/develop/clients/sch)\nfor more information about SCH.\n\n> [!NOTE]\n> Using SCH with go-redis requires v9.16.0 or later for\n> standard routing, and v9.18.0 or later for\n> [OSS Cluster API](https://redis.io/docs/latest/operate/rs/databases/configure/oss-cluster-api) connections.\n\nBy default, `go-redis` always attempts to connect via SCH but falls back to\na non-SCH connection if the server doesn't support it. However, you can configure SCH\nexplicitly by passing a `MaintNotificationsConfig` object during the connection,\nas shown in the following example:\n\n[code example]\n\n> [!NOTE]\n> SCH requires the [RESP3](https://redis.io/docs/latest/develop/reference/protocol-spec#resp-versions)\n> protocol, so you must set `Protocol:3` explicitly when you connect.\n\nThe `maintnotifications.Config` object accepts the following parameters:\n\n| Name | Description |\n|------ |------------- |\n| `Mode` | Whether or not to enable SCH. The options are `ModeDisabled`, `ModeEnabled` (require SCH and abort the connection if not supported), and `ModeAuto` (require SCH and fall back to a non-SCH connection if not supported). The default is `ModeAuto`.   |\n| `EndpointType` | The type of endpoint to use for the connection. The options are `EndpointTypeExternalIP`, `EndpointTypeInternalIP`, `EndpointTypeExternalFQDN`, `EndpointTypeInternalFQDN`, `EndpointTypeAuto` (auto-detect based on connection), and `EndpointTypeNone` (reconnect with current config). The default is `EndpointTypeAuto`. |\n| `HandoffTimeout` | The timeout to connect to the replacement node. The default is 15 seconds. |\n| `RelaxedTimeout` | The timeout to use for commands and connections while the server is performing maintenance. The default is 10 seconds. |\n| `PostHandoffRelaxedDuration` | The duration to continue using relaxed timeouts after a successful handoff (this provides extra resilience during cluster transitions). The default is 20 seconds. |\n| `MaxHandoffRetries` | The maximum number of times to retry connecting to the replacement node. The default is 3. |\n\n> [!NOTE]\n>  Redis Cloud supports relaxed timeouts *only* (and not pre-handoffs) for SCH if you are using\n> either [AWS PrivateLink](https://redis.io/docs/latest/operate/rc/security/aws-privatelink) or\n> [Google Cloud Private Service Connect](https://redis.io/docs/latest/operate/rc/security/private-service-connect)\n> (see [Smart client handoffs](https://redis.io/docs/latest/develop/clients/sch#redis-cloud) for more information).\n> To use relaxed timeouts with these services, you should set `EndpointType: maintnotifications.EndpointTypeNone`\n> when you connect. All other configurations have full support for both relaxed timeouts and pre-handoffs."
    },
    {
      "id": "connect-using-client-side-caching",
      "title": "Connect using client-side caching",
      "role": "content",
      "text": "Client-side caching is a technique to reduce network traffic between\nthe client and server, resulting in better performance. See\n[Client-side caching introduction](https://redis.io/docs/latest/develop/clients/client-side-caching)\nfor more information about how client-side caching works and how to use it effectively.\n\n> [!NOTE]\n> Client-side caching is an experimental feature of go-redis and its\n> API may change in a minor release.\n>\n> Client-side caching requires go-redis v9.22.0 or later.\n> To maximize compatibility with all Redis products, client-side caching\n> is supported by Redis v7.4 or later.\n>\n> Client-side caching requires the [RESP3](https://redis.io/docs/latest/develop/reference/protocol-spec#resp-versions)\n> protocol, so you must set `Protocol: 3` explicitly when you connect. On a RESP2\n> connection, client-side caching silently does nothing. It is also limited to\n> standalone clients and to logical database 0; on any other database it is\n> disabled with a log warning.\n\nTo enable client-side caching, pass a `ClientSideCacheConfig` object when you\nconnect on a `Protocol: 3` client. Passing an empty `ClientSideCacheConfig{}`\nenables caching with the default settings:\n\n[code example]\n\nYou can see the cache working if you connect to the same Redis database\nwith [`redis-cli`](https://redis.io/docs/latest/develop/tools/cli) and run the\n[`MONITOR`](https://redis.io/docs/latest/commands/monitor) command. With caching enabled,\nthe server sees the first `Get(\"city\")` call but not the second, which the\nclient satisfies from the cache."
    },
    {
      "id": "how-invalidation-works",
      "title": "How invalidation works",
      "role": "content",
      "text": "Redis tracks the keys each connection reads and sends an invalidation message\nwhen one of them changes. go-redis keeps a single cache shared by every\nconnection in the client's pool: each connection enables tracking on the\nserver, and go-redis applies the invalidation messages in the background.\n\nBecause invalidation is asynchronous, an entry is evicted shortly after the\ndata changes rather than at the instant of the write. Use `DrainInterval` to\ncontrol how often invalidations are applied, and `MaxStaleness` to put a hard\ntime limit on how long any entry can be served (see\n[Configuration options](#configuration-options) for more information)."
    },
    {
      "id": "configuration-options",
      "title": "Configuration options",
      "role": "configuration",
      "text": "The `ClientSideCacheConfig` object accepts the following options to tune the\ncache:\n\n| Name | Description |\n| :-- | :-- |\n| `MaxEntries` | The maximum number of entries the cache can hold. Zero or negative means unlimited. If both `MaxEntries` and `MaxMemoryBytes` are unlimited, `MaxEntries` defaults to 10,000 so the cache cannot grow without bound. |\n| `MaxMemoryBytes` | An approximate memory limit for the cache. Zero or negative means unlimited. The cache is divided into 16 shards that each enforce a 16th of this limit, so set it to at least 16 times the size of your largest cached reply. |\n| `MaxStaleness` | The longest time an entry can be served after it was cached, regardless of invalidation. This is a safety net for a missed invalidation rather than the main way entries are kept fresh, so set it well above the time an invalidation takes to arrive. Zero, the default, disables it. |\n| `DrainInterval` | How often go-redis checks idle connections for invalidation messages and applies them. The default is 5ms and the minimum is 1ms. |"
    },
    {
      "id": "monitoring-the-cache",
      "title": "Monitoring the cache",
      "role": "content",
      "text": "Use the `CSCStats()` method to read the cache statistics for a client:\n\n[code example]"
    },
    {
      "id": "supplying-your-own-cache",
      "title": "Supplying your own cache",
      "role": "content",
      "text": "Set the `ClientSideCache` option to use your own cache instead of the built-in\none. It accepts any value that implements the\n[`Cache`](https://pkg.go.dev/github.com/redis/go-redis/v9#Cache) interface and\ntakes precedence over `ClientSideCacheConfig`. You can also use it to share a\nsingle cache between several clients, but only when those clients connect to the\nsame server and database.\n\nThe simplest approach is to wrap the built-in cache, which `NewLocalCache()`\nreturns, and override only the methods you want to change. The example below\ncounts lookups and passes everything else through:\n\n[code example]\n\n> [!NOTE]\n> Embed the concrete `*redis.LocalCache` type, as shown above, rather\n> than the `Cache` interface. Cache statistics come from an optional `Stats()`\n> method that the `Cache` interface doesn't declare, so a wrapper that embeds the\n> interface still compiles but makes `CSCStats()` report zeros.\n\nTo write a cache from scratch, you should implement all eight `Cache` methods: `Get()` for\nlookups, `Reserve()`, `FulfillOwned()`, and `Cancel()` to ensure that only one\ncaller fetches a missing key, and `DeleteByRedisKey()`, `DeleteByCacheKey()`,\n`EvictByConn()`, and `Flush()` to remove entries when invalidation arrives.\ngo-redis calls these methods from several goroutines at once, so your\nimplementation must be thread-safe, and must treat cache keys and Redis keys as\nopaque strings and preserve them exactly. It must also stop waiting for an\nin-progress reservation when the context is canceled. You should also implement\n`Stats() redis.CSCStats` if you want to use the `CSCStats()` function with your cache.\n\nIf you only want to change how the cache estimates the memory used by an entry, you\ndon't need a full cache implementation. Instead, set the `Sizer` field of\n`ClientSideCacheConfig` to a function that returns a size in bytes. The\nbuilt-in cache will then use it in place of its own approximation."
    }
  ],
  "examples": [
    {
      "id": "basic-connection-ex0",
      "language": "go",
      "code": "import (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc main() {    \n    client := redis.NewClient(&redis.Options{\n        Addr:\t  \"localhost:6379\",\n        Password: \"\", // No password set\n        DB:\t\t  0,  // Use default DB\n        Protocol: 2,  // Connection protocol\n    })\n}",
      "section_id": "basic-connection"
    },
    {
      "id": "basic-connection-ex1",
      "language": "go",
      "code": "opt, err := redis.ParseURL(\"redis://<user>:<pass>@localhost:6379/<db>\")\nif err != nil {\n\tpanic(err)\n}\n\nclient := redis.NewClient(opt)",
      "section_id": "basic-connection"
    },
    {
      "id": "basic-connection-ex2",
      "language": "go",
      "code": "ctx := context.Background()\n\nerr := client.Set(ctx, \"foo\", \"bar\", 0).Err()\nif err != nil {\n    panic(err)\n}\n\nval, err := client.Get(ctx, \"foo\").Result()\nif err != nil {\n    panic(err)\n}\nfmt.Println(\"foo\", val)",
      "section_id": "basic-connection"
    },
    {
      "id": "connect-to-a-redis-cluster-ex0",
      "language": "go",
      "code": "client := redis.NewClusterClient(&redis.ClusterOptions{\n    Addrs: []string{\":16379\", \":16380\", \":16381\", \":16382\", \":16383\", \":16384\"},\n\n    // To route commands by latency or randomly, enable one of the following.\n    //RouteByLatency: true,\n    //RouteRandomly: true,\n})",
      "section_id": "connect-to-a-redis-cluster"
    },
    {
      "id": "connect-to-redis-sentinel-ex0",
      "language": "go",
      "code": "client := redis.NewFailoverClient(&redis.FailoverOptions{\n    MasterName:    \"mymaster\",\n    SentinelAddrs: []string{\"localhost:26379\", \"localhost:26380\", \"localhost:26381\"},\n})",
      "section_id": "connect-to-redis-sentinel"
    },
    {
      "id": "connect-to-redis-sentinel-ex1",
      "language": "go",
      "code": "client := redis.NewFailoverClient(&redis.FailoverOptions{\n    MasterName:       \"mymaster\",\n    SentinelAddrs:    []string{\"localhost:26379\", \"localhost:26380\", \"localhost:26381\"},\n    SentinelPassword: \"sentinel-secret\", // use your Sentinel password\n    Username:         \"default\",         // use your Redis user\n    Password:         \"secret\",          // use your Redis password\n})",
      "section_id": "connect-to-redis-sentinel"
    },
    {
      "id": "connect-to-redis-sentinel-ex2",
      "language": "go",
      "code": "replica := redis.NewFailoverClient(&redis.FailoverOptions{\n    MasterName:    \"mymaster\",\n    SentinelAddrs: []string{\"localhost:26379\", \"localhost:26380\", \"localhost:26381\"},\n    ReplicaOnly:   true,\n})",
      "section_id": "connect-to-redis-sentinel"
    },
    {
      "id": "connect-to-your-production-redis-with-tls-ex0",
      "language": "go",
      "code": "// Load client cert\ncert, err := tls.LoadX509KeyPair(\"redis_user.crt\", \"redis_user_private.key\")\nif err != nil {\n    log.Fatal(err)\n}\n\n// Load CA cert\ncaCert, err := os.ReadFile(\"redis_ca.pem\")\nif err != nil {\n    log.Fatal(err)\n}\ncaCertPool := x509.NewCertPool()\ncaCertPool.AppendCertsFromPEM(caCert)\n\nclient := redis.NewClient(&redis.Options{\n    Addr:     \"my-redis.cloud.redislabs.com:6379\",\n    Username: \"default\", // use your Redis user. More info https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/\n    Password: \"secret\", // use your Redis password\n    TLSConfig: &tls.Config{\n        MinVersion:   tls.VersionTLS12,\n        Certificates: []tls.Certificate{cert},\n        RootCAs:      caCertPool,\n    },\n})\n\n//send SET command\nerr = client.Set(ctx, \"foo\", \"bar\", 0).Err()\nif err != nil {\n    panic(err)\n}\n\n//send GET command and print the value\nval, err := client.Get(ctx, \"foo\").Result()\nif err != nil {\n    panic(err)\n}\nfmt.Println(\"foo\", val)",
      "section_id": "connect-to-your-production-redis-with-tls"
    },
    {
      "id": "connect-using-smart-client-handoffs-sch-ex0",
      "language": "go",
      "code": "rdb := redis.NewClient(&redis.Options{\n    Addr:     \"localhost:6379\",\n    Protocol: 3, // RESP3 required\n    MaintNotificationsConfig: &maintnotifications.Config{\n            Mode:                       maintnotifications.ModeEnabled,\n            EndpointType:               maintnotifications.EndpointTypeExternalIP,\n            HandoffTimeout:             10 * time.Second,\n            RelaxedTimeout:             10 * time.Second,\n            PostHandoffRelaxedDuration: 10 * time.Second,\n            MaxHandoffRetries:          5,\n    },\n})",
      "section_id": "connect-using-smart-client-handoffs-sch"
    },
    {
      "id": "connect-using-client-side-caching-ex0",
      "language": "go",
      "code": "import (\n    \"context\"\n    \"github.com/redis/go-redis/v9\"\n)\n\nfunc main() {\n    ctx := context.Background()\n\n    client := redis.NewClient(&redis.Options{\n        Addr:                  \"localhost:6379\",\n        Protocol:              3, // RESP3 required for client-side caching\n        ClientSideCacheConfig: &redis.ClientSideCacheConfig{},\n    })\n\n    client.Set(ctx, \"city\", \"New York\", 0)\n    client.Get(ctx, \"city\") // Retrieved from the server and cached\n    client.Get(ctx, \"city\") // Retrieved from the cache\n}",
      "section_id": "connect-using-client-side-caching"
    },
    {
      "id": "monitoring-the-cache-ex0",
      "language": "go",
      "code": "stats := client.CSCStats()\nfmt.Printf(\"Cache hits: %d, misses: %d\\n\", stats.Hits, stats.Misses)\nfmt.Printf(\"Entries: %d, memory: %d bytes\\n\", stats.Entries, stats.MemoryUsageBytes)",
      "section_id": "monitoring-the-cache"
    },
    {
      "id": "supplying-your-own-cache-ex0",
      "language": "go",
      "code": "type countingCache struct {\n    *redis.LocalCache\n    lookups atomic.Int64\n}\n\nfunc (c *countingCache) Get(ctx context.Context, cacheKey string) ([]byte, bool) {\n    c.lookups.Add(1)\n    return c.LocalCache.Get(ctx, cacheKey)\n}\n\ncache := &countingCache{\n    LocalCache: redis.NewLocalCache(redis.ClientSideCacheConfig{MaxEntries: 1000}),\n}\n\nclient := redis.NewClient(&redis.Options{\n    Addr:            \"localhost:6379\",\n    Protocol:        3,\n    ClientSideCache: cache,\n})",
      "section_id": "supplying-your-own-cache"
    }
  ]
}
