Nov 12, 20268 min read

ElastiCache vs Memorystore for Redis: AWS and GCP Caches Compared

How Amazon ElastiCache and Google Memorystore for Redis differ on engines, serverless and node-based options, high availability, sizing, networking, auth and billing, and how Encore provisions either one from a cache declared in TypeScript or Go.

Illustration for ElastiCache vs Memorystore for Redis: AWS and GCP Caches Compared

ElastiCache and Memorystore are the default managed Redis services on their clouds, since the cache usually sits next to whichever cloud runs the rest of the backend. ElastiCache covers Valkey, Redis OSS and Memcached on AWS with a serverless mode and node-based clusters. Memorystore for Redis is Google Cloud's instance-based Redis with a standalone and a replicated tier, and the two part ways on sizing, failover, network setup and how clients authenticate.

This comparison goes through those differences, the cases where each one fits, and how Encore provisions either cache from the same TypeScript or Go declaration.

ElastiCache vs Memorystore at a glance

Encore cache clusterAmazon ElastiCacheMemorystore for Redis
EnginesRedisValkey, Redis OSS, MemcachedRedis
Deployment optionsElastiCache on AWS, Memorystore on GCPServerless or node-based clustersBasic Tier or Standard Tier instances
High availabilityMulti-AZ on AWS, HA setup on GCPMulti-AZ replicas with automatic failoverStandard Tier cross-zone replica with automatic failover
Size limitsStarts on cache.m6g.large on AWS, smallest size on GCPSet by node type and shard count, or scales on serverlessUp to 300 GB primary, up to five read replicas
NetworkPrivate subnets created per environmentInside your VPC, security groupsVPC peering, direct peering by default
AuthRedis ACLs on AWS, managed AUTH on GCPRedis ACLs or AUTH tokenAUTH string (UUID), optional TLS
Cross-regionPer environmentGlobal Datastore on node-based clustersNo
Local developmentencore run starts an in-memory RedisYour own RedisYour own Redis

How does Encore provision ElastiCache and Memorystore from code?

Encore

Encore works as infrastructure from code for TypeScript and Go: a cache cluster declared in a service is provisioned as a separate Redis instance in your own cloud account, and the cloud you connect decides which managed service that is. The AWS infrastructure docs describe ElastiCache for Redis starting on cache.m6g.large with Multi-AZ replication and Redis ACLs, and the GCP infrastructure docs describe Memorystore for Redis in a high-availability setup, with AUTH credentials managed and rotated by the Encore platform.

Application code passes through Encore and infrastructure guardrails to resources provisioned in your own AWS or GCP account.
Encore provisions the infrastructure your application needs in your own AWS or GCP account.

Set up the app

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create shop --example=ts/hello-world$ cd shop && mkdir -p catalog/migrations

The first migration creates the catalog table, including updated_at, which the cache uses to refuse a stale write:

-- catalog/migrations/1_products.up.sql CREATE TABLE products ( id TEXT PRIMARY KEY, name TEXT NOT NULL, price_cents INT NOT NULL, stock INT NOT NULL, updated_at TIMESTAMPTZ NOT NULL DEFAULT now() );

A product catalog is a typical read-through cache: product pages are read constantly, prices change occasionally, and a stale price after an update is the bug to avoid. The catalog directory is a service, marked by its encore.service.ts file:

// catalog/encore.service.ts import { Service } from "encore.dev/service"; export default new Service("catalog");

The cluster, a typed keyspace and the invalidation live in the service that owns the data:

// catalog/catalog.ts import { api, APIError } from "encore.dev/api"; import { CacheCluster, StructKeyspace, expireInMinutes } from "encore.dev/storage/cache"; import { SQLDatabase } from "encore.dev/storage/sqldb"; const db = new SQLDatabase("catalog", { migrations: "./migrations" }); // ElastiCache for Redis on AWS, Memorystore for Redis on GCP, in-memory Redis locally. const cache = new CacheCluster("catalog-cache", { evictionPolicy: "allkeys-lru" }); interface Product { id: string; name: string; priceCents: number; stock: number; updatedAt: string; // ISO timestamp from the products.updated_at column } // Product pages are read far more often than they change. const products = new StructKeyspace<{ id: string }, Product>(cache, { keyPattern: "product/:id", defaultExpiry: expireInMinutes(10), }); export const getProduct = api( { expose: true, method: "GET", path: "/products/:id" }, async ({ id }: { id: string }): Promise<Product> => { const cached = await products.get({ id }); if (cached) return cached; const row = await db.queryRow<{ id: string; name: string; price_cents: number; stock: number; updated_at: Date }>` SELECT id, name, price_cents, stock, updated_at FROM products WHERE id = ${id} `; if (!row) throw APIError.notFound("product not found"); const product: Product = { id: row.id, name: row.name, priceCents: row.price_cents, stock: row.stock, updatedAt: row.updated_at.toISOString(), }; // Do not overwrite a newer cache entry written by updatePrice. const latest = await products.get({ id }); if (!latest || latest.updatedAt < product.updatedAt) { await products.set({ id }, product); } return latest && latest.updatedAt >= product.updatedAt ? latest : product; }, ); export const updatePrice = api( { expose: true, method: "POST", path: "/products/:id/price" }, async ({ id, priceCents }: { id: string; priceCents: number }): Promise<void> => { const row = await db.queryRow<{ id: string; name: string; price_cents: number; stock: number; updated_at: Date }>` UPDATE products SET price_cents = ${priceCents}, updated_at = now() WHERE id = ${id} RETURNING id, name, price_cents, stock, updated_at `; if (!row) throw APIError.notFound("product not found"); // Write through the new price so a concurrent miss cannot restore the old one. await products.set({ id }, { id: row.id, name: row.name, priceCents: row.price_cents, stock: row.stock, updatedAt: row.updated_at.toISOString(), }); }, );

StructKeyspace stores the product as JSON under the key product/<id>, and get returns undefined on a miss, so the type checker catches code that forgets the database fallback. The caching docs list the other keyspace types, such as counters, lists and sets, the eviction policies and CacheCluster.named() for sharing one cluster between services. encore run starts the cache in memory and Postgres locally, so the miss path, the hit path and the invalidation can all be exercised on a laptop.

The declaration carries no node type, tier, subnet group or AUTH setting, and those are chosen per environment by the Encore platform and can be adjusted afterwards in the cloud console or the Encore dashboard, per the infrastructure configuration docs. An agent asked to cache a slow endpoint adds a keyspace in the same pull request as the endpoint change, and the cache exists in every environment after the next deploy.

Best fit: TypeScript and Go teams who want a Redis cache next to their services on AWS or GCP, created in their own account from the code that reads and writes it, with the same code on both clouds.

Amazon ElastiCache

Amazon ElastiCache

ElastiCache runs the Valkey, Redis OSS and Memcached engines in your VPC. ElastiCache Serverless creates a highly available cache without choosing node types or shard counts, and bills for data stored plus ElastiCache Processing Units, which count both vCPU time and data transferred, per the ElastiCache pricing page. Node-based clusters let you pick instance types, shards and replicas, and add cluster mode for sharding and Multi-AZ replicas with automatic failover.

Clients authenticate with Redis ACL users or an AUTH token, and access is otherwise limited by security groups, so an ECS task or Lambda function needs to be in the VPC with a rule that allows port 6379. Node-based clusters can be linked across regions with Global Datastore, which is not available for serverless caches.

The choice between serverless and node-based is the main design decision: serverless suits uneven traffic and teams that do not want to size nodes, while node-based clusters give predictable cost at steady load, reserved node pricing and cross-region replication. Both are usually described in Terraform or CloudFormation with a subnet group, a parameter group, security groups and the auth configuration.

Best fit: Backends on AWS that need a cache or Memcached inside their VPC, especially when a serverless cache or cross-region replication matters.

Memorystore for Redis

Memorystore for Redis

Memorystore for Redis offers two tiers, as Google's Memorystore for Redis overview describes: Basic Tier is a standalone instance with no replication, and Standard Tier replicates across zones with automatic failover and can scale reads across up to five read replicas. Both tiers go up to a 300 GB primary, and scaling a Standard Tier instance causes under a minute of downtime according to the same page.

Instances live in a Google-managed network and are reached over VPC peering. New instances use direct peering by default, and Shared VPC setups need a private services access connection created before the instance, per the networking docs. Cloud Run reaches the instance through Direct VPC egress or a Serverless VPC Access connector.

AUTH is optional and uses a generated UUID as the password, and Google notes in the AUTH docs that without in-transit encryption the AUTH command is not guaranteed to be encrypted end to end, so production setups usually enable both. Larger or sharded workloads move to Memorystore for Redis Cluster or Memorystore for Valkey, which are separate products with their own connectivity model.

Best fit: Backends on Cloud Run or GKE that want a single Redis instance, replicated or not, inside their GCP network.

How to choose

Pick Encore when the cache belongs to TypeScript or Go services and you want ElastiCache or Memorystore created in your own account from the declaration in code, with an in-memory Redis under encore run and the same keyspaces on either cloud. Pick ElastiCache directly when you need Memcached, ElastiCache Serverless, Global Datastore or a cache shared with workloads outside your Encore services. Pick Memorystore for Redis directly when you are on GCP, a single instance up to 300 GB covers the dataset, and you manage the network and tier settings alongside other Google Cloud resources.

Frequently asked questions

What is the difference between ElastiCache and Memorystore?

ElastiCache is AWS's managed in-memory cache for the Valkey, Redis OSS and Memcached engines, offered as ElastiCache Serverless or node-based clusters inside your VPC. Memorystore for Redis is Google Cloud's managed Redis, offered as a Basic Tier standalone instance or a Standard Tier instance with cross-zone replication, up to 300 GB, reached over a VPC peering connection.

Does Memorystore for Redis support read replicas?

Standard Tier instances with read replicas enabled can scale reads across up to five replicas through a read endpoint, according to Google's Memorystore for Redis overview. Basic Tier instances have no replication and no automatic failover.

Is ElastiCache Serverless the same as Memorystore?

ElastiCache Serverless has no instances or nodes to size and bills for data stored and ElastiCache Processing Units, while a Memorystore for Redis instance has a provisioned size and tier that you choose and scale yourself. For sharded workloads Google offers the separate Memorystore for Redis Cluster and Memorystore for Valkey products.

How do I use the same Redis cache code on AWS and GCP?

With Encore, declare new CacheCluster("catalog-cache", { evictionPolicy: "allkeys-lru" }) and a typed keyspace such as StructKeyspace in TypeScript. Deployed to AWS it becomes ElastiCache for Redis, deployed to GCP it becomes Memorystore for Redis, and under encore run it runs as an in-memory Redis on your machine.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders