Repository navigation
Context Caching
Context caching stores a large context once and reuses it across many requests. The context can be documents, files, conversation history or a system instruction. Cached tokens are billed at a lower rate than regular input tokens, and responses can come back faster. In this SDK, CachingClient creates and manages caches, and GenerativeModel.CachedContent attaches a cache to a model.
Package: Google_GenerativeAI. Namespaces: GenerativeAI.Clients (CachingClient) and GenerativeAI.Types (CachedContent, Duration).
This page documents caching on the Gemini Developer API, which is the platform covered by the SDK's caching tests.
Every GenerativeModel has a ready-made CachingClient property. You can also create a client from a platform adapter:
using GenerativeAI;
using GenerativeAI.Clients;
using GenerativeAI.Types;
var googleAi = new GoogleAi("YOUR_API_KEY");
var model = googleAi.CreateGenerativeModel(GoogleAIModels.Gemini38Flash);
CachingClient cachingClient = model.CachingClient!;
// Or standalone
var platform = new GoogleAIPlatformAdapter("YOUR_API_KEY");
var cachingClient2 = new CachingClient(platform);| Method | Description |
|---|---|
CreateCachedContentAsync(CachedContent) |
Creates a cache from contents, a system instruction, tools and a TTL or expiry |
GetCachedContentAsync(name) |
Gets a cache by name (cachedContents/{id} or just {id}) |
ListCachedContentsAsync(pageSize, pageToken) |
Lists caches, one page at a time |
UpdateCachedContentAsync(cacheName, cachedContent, updateMask) |
Updates ttl or expireTime (PATCH) |
DeleteCachedContentAsync(name) |
Deletes a cache |
All methods accept a CancellationToken.
| Property | Notes |
|---|---|
Model |
Required. Must match the model you'll use, for example GoogleAIModels.Gemini38Flash (models/gemini-3.8-flash) |
Contents |
The content to cache (List<Content>) |
SystemInstruction |
Optional Content
|
Tools, ToolConfig
|
Optional tools stored with the cache |
Ttl |
Duration, for example new Duration { Seconds = 3600 }, or TimeSpan.FromHours(1) through the implicit conversion |
ExpireTime |
Timestamp. Use it instead of Ttl. Converts implicitly from DateTime
|
DisplayName |
Optional friendly name |
KmsKeyName |
Customer-managed encryption key (a Vertex AI field) |
Name, CreateTime, UpdateTime, UsageMetadata
|
Output only |
var longDocument = await File.ReadAllTextAsync("path/to/long-document.txt");
var cachedContent = new CachedContent
{
DisplayName = "Product Documentation Cache",
Model = GoogleAIModels.Gemini38Flash, // must match the model you'll use later
Contents = new List<Content>
{
new Content(longDocument, Roles.User)
},
Ttl = new Duration { Seconds = 3600 } // expires after 1 hour
};
CachedContent createdCache = await cachingClient.CreateCachedContentAsync(cachedContent);
Console.WriteLine($"Cache created: {createdCache.Name}");
Console.WriteLine($"Expires at: {createdCache.ExpireTime}");
Console.WriteLine($"Token count: {createdCache.UsageMetadata?.TotalTokenCount}");var cache = await cachingClient.CreateCachedContentAsync(new CachedContent
{
DisplayName = "Customer Support Bot Cache",
Model = GoogleAIModels.Gemini38Flash,
SystemInstruction = new Content("You are a helpful customer support agent. Be professional and concise.", null),
Contents = new List<Content>
{
new Content("Company policies and FAQs:\n\n[Large document content here]", Roles.User)
},
Ttl = TimeSpan.FromHours(2)
});var multiCache = await cachingClient.CreateCachedContentAsync(new CachedContent
{
DisplayName = "Multi-Document Cache",
Model = GoogleAIModels.Gemini38Flash,
Contents = new List<Content>
{
new Content("Document 1: Product Specifications\n\n" + doc1, Roles.User),
new Content("I've processed the product specifications.", Roles.Model),
new Content("Document 2: User Manual\n\n" + doc2, Roles.User)
},
Ttl = new Duration { Seconds = 7200 }
});Uploaded files can be cached as well. Add parts that reference a RemoteFile from Files Client.
Set the model's CachedContent property. Every request then sends the cache name.
var model = new GenerativeModel(platform, GoogleAIModels.Gemini38Flash)
{
CachedContent = createdCache
};
var response1 = await model.GenerateContentAsync("What are the main features of this product?");
Console.WriteLine(response1.Text());
// Reuses the same cached context
var response2 = await model.GenerateContentAsync("What is the pricing structure?");
Console.WriteLine(response2.Text());
Console.WriteLine($"Cached tokens used: {response2.UsageMetadata?.CachedContentTokenCount}");You can also attach an existing cache to a model you already have:
CachedContent? retrieved = await cachingClient.GetCachedContentAsync("cachedContents/your-cache-id");
model.CachedContent = retrieved;When CachedContent is set, the SDK:
- throws
ArgumentExceptionifmodel.Modelis not exactly equal toCachedContent.Model; - removes
Tools,ToolConfigandSystemInstructionfrom the request, because they must be part of the cache instead; - throws
NotSupportedExceptionif Google Search, code execution or legacy grounding is enabled on the model.
To set the cache per request instead, set GenerateContentRequest.CachedContent to the cache name.
var cachedList = await cachingClient.ListCachedContentsAsync(pageSize: 10);
foreach (var item in cachedList.CachedContents ?? new List<CachedContent>())
{
Console.WriteLine($"{item.Name} | {item.DisplayName} | {item.Model} | created {item.CreateTime} | expires {item.ExpireTime}");
}
if (!string.IsNullOrEmpty(cachedList.NextPageToken))
{
var nextPage = await cachingClient.ListCachedContentsAsync(10, cachedList.NextPageToken);
}
var specificCache = await cachingClient.GetCachedContentAsync("cachedContents/your-cache-id");
Console.WriteLine($"Retrieved cache: {specificCache?.DisplayName}");Only ttl and expireTime can change after a cache is created. Use updateMask to name the field you're changing.
var updatedCache = await cachingClient.UpdateCachedContentAsync(
cacheName: createdCache.Name!,
cachedContent: new CachedContent { Ttl = new Duration { Seconds = 7200 } },
updateMask: "ttl");
Console.WriteLine($"New expiration: {updatedCache?.ExpireTime}");
// Or set an absolute expiry
await cachingClient.UpdateCachedContentAsync(createdCache.Name!,
new CachedContent { ExpireTime = DateTime.UtcNow.AddHours(4) }, "expireTime");await cachingClient.DeleteCachedContentAsync(createdCache.Name!);using GenerativeAI;
using GenerativeAI.Clients;
using GenerativeAI.Exceptions;
using GenerativeAI.Types;
var apiKey = System.Environment.GetEnvironmentVariable("GOOGLE_API_KEY"); // "System." avoids a clash with GenerativeAI.Types.Environment
var platform = new GoogleAIPlatformAdapter(apiKey);
var cachingClient = new CachingClient(platform);
using var httpClient = new HttpClient();
var largeContext = await httpClient.GetStringAsync(
"https://storage.googleapis.com/generativeai-downloads/data/a11.txt");
var cache = await cachingClient.CreateCachedContentAsync(new CachedContent
{
DisplayName = "Apollo 11 transcript",
Model = GoogleAIModels.Gemini38Flash,
SystemInstruction = new Content("You are an expert on the Apollo program.", null),
Contents = new List<Content> { new Content($"Transcript:\n\n{largeContext}", Roles.User) },
Ttl = TimeSpan.FromMinutes(30)
});
Console.WriteLine($"Cache created: {cache.Name}, tokens: {cache.UsageMetadata?.TotalTokenCount}");
try
{
var model = new GenerativeModel(platform, GoogleAIModels.Gemini38Flash) { CachedContent = cache };
foreach (var question in new[]
{
"Summarize the main events.",
"What problems did the crew report?",
"Describe the landing sequence."
})
{
var response = await model.GenerateContentAsync(question);
Console.WriteLine($"\nQ: {question}\nA: {response.Text()}");
}
}
finally
{
await cachingClient.DeleteCachedContentAsync(cache.Name!);
}API errors throw ApiException. For example, you can retry once when rate limited:
using GenerativeAI.Exceptions;
async Task<CachedContent?> CreateCacheWithRetry(CachingClient client, CachedContent content)
{
try
{
return await client.CreateCachedContentAsync(content);
}
catch (ApiException ex) when (ex.ErrorCode == 429)
{
await Task.Delay(TimeSpan.FromSeconds(5));
return await client.CreateCachedContentAsync(content);
}
catch (ApiException ex)
{
Console.WriteLine($"Failed to create cache: {ex.ErrorCode} {ex.ErrorStatus} {ex.ErrorMessage}");
return null;
}
}Getting or deleting a cache that doesn't exist also throws.
- Cost savings: Cached tokens are billed at a lower rate than regular input tokens.
- Performance: The cached context isn't processed again on every request.
- Consistency: Every request uses the same context.
- Large context: You can cache content up to the model's context window.
-
Model matching:
CachedContent.Modelmust equalGenerativeModel.Modelexactly. Use the same constant for both. - Tool restrictions: You can't combine Google Search, code execution or grounding with a cache on the model. Tools, tool config and system instructions belong in the cache.
-
Immutability: Content, system instruction, tools and model can't change after creation. Only
ttlandexpireTimecan. -
TTL management: Caches expire automatically. Extend them with
UpdateCachedContentAsync. - Minimum size: Each model has a minimum number of tokens it will cache, and it differs between models. Check the Gemini caching docs for current limits.
- Cost structure: Creating and storing a cache costs money (storage is billed per token-hour). Delete caches you no longer need.
-
Resource names: You can pass names as
cachedContents/{id}or{id}.
Good fit: analysing large documents with many questions, RAG with a fixed corpus, multi-turn conversations over the same material, code-repository analysis, support bots with large knowledge bases, educational, legal or medical document Q&A.
Not a good fit: one-off queries, context that changes often, small contexts below the model's minimum, and very short sessions where the cost of creating the cache isn't recovered.
- Ask as many questions per cache as you can, to spread the creation cost.
- Choose a TTL that matches how long you'll actually use the cache.
- Reuse caches for recurring workloads instead of creating new ones.
- Delete caches when you're done.
Getting Started
- Initialization
- Authentication
- Configuration & Error Handling
- Supported Models
- Migration Guide (v4)
- Release Notes (v4)
Core Features
- Generate Content
- Chat Session
- Streaming
- Multimodal Features
- JSON Mode
- Function Calling
- Embeddings
- Context Caching
Gemini APIs
- Interactions API
- Multimodal Live API
- File Search
- Batch API
- Model Tuning
- Webhooks
- Agent APIs
- Image Generation
- Video Generation
- Speech Generation
- Files Client
- Model Client
Vertex AI
Integrations
Guides
Legacy