google-genai
Google's current first-party Python SDK for Gemini, and the replacement for the deprecated google-generativeai package. One genai.Client covers both the Gemini Developer API (API key from AI Studio) and the Gemini Enterprise Agent Platform, the enterprise product formerly called Vertex AI. It wraps text and multimodal generation, streaming, multi-turn chats, function calling with automatic execution, structured JSON output, file uploads, context caching, embeddings, and Imagen image plus Veo video generation, with a mirrored async client under client.aio.
The only sensible SDK for direct Gemini work in Python today: capable, current, and unusually honest about its own upcoming breakage. Pin your version and read the 3.0 migration table before you upgrade.
Use it if
- You call Gemini directly and want the SDK Google actually maintains, not the deprecated google-generativeai package your older tutorials show
- You need one codebase serving both an API-key prototype and an enterprise Google Cloud deployment; the same client switches with a constructor flag
- You want function calling where you pass a plain Python function and the SDK runs the call-and-respond loop for you
- You need the full multimodal surface: files, context caching, embeddings, Imagen, Veo, and live audio
- You might switch model providers later; this SDK is Gemini-only by design, and a call layer like litellm keeps you portable
- You dislike moving targets: the README itself warns of breaking changes in the next major (automatic function calling moves to Chats, Live API methods removed) and tells you to pin below 3.0.0
- You expect stable endpoints by default; the SDK targets Google's beta API unless you explicitly set api_version to v1
- You maintain legacy google-generativeai code you cannot migrate yet; the two packages have different imports and call shapes, and snippets do not transfer
Setup reality
pip install google-genai, grab a key from AI Studio, and generate_content works in four lines. The sharp edges: two auth worlds (API key vs enterprise project and location) configured through constructor args or a pile of env vars, where GOOGLE_API_KEY silently wins over GEMINI_API_KEY if both are set; the client defaults to beta endpoints unless you pass http_options with api_version set to v1; long-lived processes should close clients or use the context managers to avoid httpx client-closed errors; and Google's own README says to pin below 3.0.0 because the next major changes automatic function calling and removes Live API methods.
Patterns
Create a client (Developer API)create-client
from google import genai
# explicit key from Google AI Studio
client = genai.Client(api_key='GEMINI_API_KEY')
# or rely on the GEMINI_API_KEY / GOOGLE_API_KEY env var
client = genai.Client()If both env vars are set, GOOGLE_API_KEY takes precedence over GEMINI_API_KEY, a classic source of wrong-project confusion.
Client for the enterprise platformenterprise-client
from google import genai
client = genai.Client(
enterprise=True,
project='your-project-id',
location='global',
)This is the product formerly called Vertex AI. The env-var route is GOOGLE_GENAI_USE_ENTERPRISE plus GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION.
Generate textbasic-generation
response = client.models.generate_content(
model='gemini-3.5-flash',
contents='Why is the sky blue?',
)
print(response.text)contents accepts a string, Parts, or full Content lists; the SDK normalizes everything to list[types.Content] before sending.
Tune generation via configgeneration-config
from google.genai import types
response = client.models.generate_content(
model='gemini-3.5-flash',
contents='Why is the sky blue?',
config=types.GenerateContentConfig(
temperature=0,
top_p=0.95,
top_k=20,
),
)Sampling knobs live inside config=, not as top-level kwargs; plain dicts work in place of the typed config if you prefer.
Stream a responsestreaming
for chunk in client.models.generate_content_stream(
model='gemini-3.5-flash',
contents='Tell me a story in 300 words.',
):
print(chunk.text, end='')Streaming is a separate method (generate_content_stream), not a flag on generate_content as in some other SDKs.
Async calls through client.aioasync-client
response = await client.aio.models.generate_content(
model='gemini-3.5-flash',
contents='Tell me a story in 300 words.',
)
print(response.text)
async for chunk in await client.aio.models.generate_content_stream(
model='gemini-3.5-flash',
contents='Tell me a story in 300 words.',
):
print(chunk.text, end='')client.aio mirrors every sync module. Note the extra await before iterating the async stream; forgetting it is the most common async mistake here.
Multi-turn chat sessionmulti-turn-chat
chat = client.chats.create(model='gemini-3.5-flash')
response = chat.send_message('tell me a story')
print(response.text)
response = chat.send_message('summarize the story in 1 sentence')
print(response.text)The chat object keeps history in process memory only; persist and replay it yourself if conversations must survive restarts.
Structured output from a Pydantic modelstructured-json
from pydantic import BaseModel
from google.genai import types
class CountryInfo(BaseModel):
name: str
population: int
capital: str
response = client.models.generate_content(
model='gemini-3.5-flash',
contents='Give me information for the United States.',
config=types.GenerateContentConfig(
response_mime_type='application/json',
response_json_schema=CountryInfo.model_json_schema(),
),
)
print(response.text)Do not repeat the schema or example JSON in the prompt; Google's docs warn output quality drops when you duplicate it.
Pass a Python function as a toolautomatic-function-calling
from google.genai import types
def get_current_weather(location: str) -> str:
"""Returns the current weather.
Args:
location: The city and state, e.g. San Francisco, CA
"""
return 'sunny'
response = client.models.generate_content(
model='gemini-3.5-flash',
contents='What is the weather like in Boston?',
config=types.GenerateContentConfig(tools=[get_current_weather]),
)
print(response.text)The SDK calls your function and feeds the result back, up to 10 remote calls by default. The 3.0 release moves this behavior to Chats, so avoid building new code on this exact path.
Upload a file and ask about itfile-upload
file = client.files.upload(file='a11.txt')
response = client.models.generate_content(
model='gemini-3.5-flash',
contents=['Could you summarize this file?', file],
)
print(response.text)The Files API exists only on the Gemini Developer API; on the enterprise platform you reference Cloud Storage URIs with types.Part.from_uri instead.
Opt out of beta endpointsstable-api-version
from google import genai
from google.genai import types
client = genai.Client(
api_key='GEMINI_API_KEY',
http_options=types.HttpOptions(api_version='v1'),
)The default is the beta API surface so preview features work; production services that want stability should pin api_version to v1 explicitly.
Migrate from google-generativeaimigrate-from-old-sdk
# old, deprecated package:
# import google.generativeai as genai
# genai.configure(api_key='...')
# model = genai.GenerativeModel('gemini-pro')
# response = model.generate_content('hi')
# new SDK:
from google import genai
client = genai.Client()
response = client.models.generate_content(
model='gemini-3.5-flash',
contents='hi',
)
print(response.text)The module paths differ (google.generativeai vs from google import genai), so both packages can coexist while you migrate file by file.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| google-generativeai | PyPI | Only for maintaining legacy code; it is deprecated and new work should not start on it |
| litellm | PyPI | You want Gemini as one option behind an OpenAI-format interface you can point at other providers |
| langchain-google-genai | PyPI | You are in the LangChain ecosystem and want Gemini wired in as a chat model there |