The old repository is now named deprecated-generative-ai-python, and its README says all support ended permanently on November 30, 2025. The Gemini API docs only show the new SDK, and Google's migration guide maps each old call to its replacement. Both packages are imported as genai in most code (import google.generativeai as genai before, from google import genai after), which makes half-migrated files easy to miss. This guide follows Google's migration guide and the google-genai README, linked at the end.
What changed
- Install
google-genaiinstead ofgoogle-generativeai, and importfrom google import genai. genai.configure(api_key=...)is replaced byclient = genai.Client(), which readsGEMINI_API_KEYorGOOGLE_API_KEY.genai.GenerativeModel(name)is gone. Passmodel=on each call toclient.models.generate_content().generation_config,safety_settingsandsystem_instructionmove into oneconfig=types.GenerateContentConfig(...)per request.stream=Trueis replaced by a separategenerate_content_stream()method.- Chats are created with
client.chats.create(model=...)instead ofmodel.start_chat(). - Files, token counting and embeddings move onto the client:
client.files,client.models.count_tokens,client.models.embed_content.
Migration steps
Swap the package
pip uninstall google-generativeai pip install -U google-genaiRemove the old package from your requirements in the same change, so nothing keeps importing it by accident. The new imports are
from google import genaiand, for typed configuration,from google.genai import types.Create a client instead of configuring the module
Before
import google.generativeai as genai genai.configure(api_key=os.environ["GEMINI_API_KEY"]) model = genai.GenerativeModel("gemini-flash-latest") response = model.generate_content("Tell me a story in 300 words") print(response.text)After
from google import genai client = genai.Client() # reads GEMINI_API_KEY or GOOGLE_API_KEY response = client.models.generate_content( model="gemini-flash-latest", contents="Tell me a story in 300 words", ) print(response.text)genai.Client(api_key=...)also works. If both environment variables are set,GOOGLE_API_KEYtakes precedence, so set only one. Code that created oneGenerativeModelper model name now passesmodel=on each call, which usually means storing the model name in configuration rather than a model object.response.textstays a property in Python.Move settings into GenerateContentConfig
Before
model = genai.GenerativeModel( "gemini-flash-latest", system_instruction="you are a story teller for kids under 5 years old", generation_config=genai.GenerationConfig( max_output_tokens=400, temperature=0.5, response_mime_type="application/json", ), ) response = model.generate_content("tell me a story in 100 words")After
from google.genai import types response = client.models.generate_content( model="gemini-flash-latest", contents="tell me a story in 100 words", config=types.GenerateContentConfig( system_instruction="you are a story teller for kids under 5 years old", max_output_tokens=400, temperature=0.5, response_mime_type="application/json", ), )Safety settings move into the same object, as a list of
types.SafetySetting. The old shorthand category names do not carry over:{"HATE": "BLOCK_ONLY_HIGH"}becomestypes.SafetySetting(category="HARM_CATEGORY_HATE_SPEECH", threshold="BLOCK_ONLY_HIGH"). The README notes that every method also accepts plain dicts in place of the typed objects.Use the streaming method
Before
response = model.generate_content("Write a cute story about cats.", stream=True) for chunk in response: print(chunk.text)After
for chunk in client.models.generate_content_stream( model="gemini-flash-latest", contents="Write a cute story about cats.", ): print(chunk.text)Create chats from the client
Before
model = genai.GenerativeModel("gemini-flash-latest") chat = model.start_chat() response = chat.send_message("Tell me a story in 100 words") response = chat.send_message("What happened after that?")After
chat = client.chats.create(model="gemini-flash-latest") response = chat.send_message(message="Tell me a story in 100 words") response = chat.send_message(message="What happened after that?") for chunk in chat.send_message_stream("Now make it shorter"): print(chunk.text)Move files, tokens and embeddings onto the client
genai.upload_file(path="a11.txt")toclient.files.upload(file="a11.txt")genai.list_files()andgenai.get_file(name=...)toclient.files.list()andclient.files.get(name=...)genai.delete_file(name=...)toclient.files.delete(name=...)model.count_tokens(text)toclient.models.count_tokens(model=..., contents=text)genai.embed_content(model="models/gemini-embedding-001", content=text)toclient.models.embed_content(model="gemini-embedding-001", contents=text)
Note the renamed arguments:
path=becomesfile=andcontent=becomescontents=. Uploaded file objects can be passed straight intocontentsalongside text.Switch async code to client.aio, and update error handling
Every service has an async twin under
client.aio:await client.aio.models.generate_content(...),client.aio.models.generate_content_stream(...)andclient.aio.chats.create(...). Errors from the service are raised asgoogle.genai.errors.APIError, with the HTTP status incode:from google.genai import errors try: client.models.generate_content(model="invalid-model-name", contents="Hi") except errors.APIError as e: log.warning("Gemini error %s: %s", e.code, e.message)
How to find every affected call
Start from the imports, then look for each old entry point. These ast-grep patterns match the syntax tree, so multi-line calls are found too:
sg run --pattern 'import google.generativeai as $ALIAS' --lang python
sg run --pattern '$GENAI.configure($$$ARGS)' --lang python
sg run --pattern '$GENAI.GenerativeModel($$$ARGS)' --lang python
sg run --pattern '$MODEL.start_chat($$$ARGS)' --lang python
sg run --pattern '$GENAI.GenerationConfig($$$ARGS)' --lang python
sg run --pattern '$GENAI.upload_file($$$ARGS)' --lang pythonAlso search for generate_content($$$ARGS) calls that pass stream=True. Because both SDKs are commonly imported as genai, $GENAI.configure can match unrelated modules; confirm the import in each file before rewriting. On Linux, sg may be a system command; ast-grep run is the same tool.
Testing the change
- Check that
google-generativeaiis gone from the lock file, not only fromrequirements.txt, so nothing imports it transitively. - Replace mocks of
genai.GenerativeModelwith a fake client passed into your code. Mocks of the old class keep passing against code that no longer calls it. - Run one real request per feature you use (plain, streamed, chat, JSON output) and one with safety settings, since the category names changed.
- Force an error with an invalid model name and confirm your handler catches
errors.APIErrorwithcode404.
Automating it
Google does not publish a codemod for this migration. Its migration guide is a side-by-side table of old and new calls, and the google-genai README recommends loading Gemini API Skills into AI coding assistants so they generate code for the new SDK instead of the deprecated one.
Versyka finds the old call sites deterministically with ast-grep patterns like the ones above, rewrites them along with the code around them (config objects, chat handling, mocks), then runs your repository's own type check and pytest in an isolated virtualenv inside a disposable sandbox. It opens a pull request only if those pass.
Was this guide helpful?
Check your own repository
Paste your package.json, requirements.txt or pyproject.toml into the free upgrade check to see which API SDKs are behind, with no account. Or let Versyka run this migration on one repository and open a pull request that has already passed your tests.