What is truly scary about a preview model shutdown is not the path you use often, but the path that rarely runs. gemini-3.1-flash-image-preview and gemini-3-pro-image-preview stop on June 25. If you use them in your main daytime generation, you will notice whether you like it or not. But if the reference sits in an aggregation batch that runs only at the start of the month, or in a fallback branch that fires only when the top model is jammed, you will not notice until the moment they stop.
As an indie developer, I once ran image processing in an app and only later noticed an old model name left on the fallback side. Because it normally passed through the top model, it failed silently only on the rare day the fallback fired. This time I will lay out, in order, a dependency audit that leaves no such oversight before the shutdown—from surfacing references to confirming after migration.
"Where you use it" is not one place
A model name scatters across more places than you would think. Listing the places to search before you start the audit reduces misses.
| Place | Easy-to-miss example |
|---|---|
| App code | Fallback branches; alternate model on retry |
| Config files | Model names hardcoded in per-environment YAML/JSON |
| Environment variables | Values set only in the deploy environment |
| Stored prompts | Job definitions recorded in a DB or files |
| Batches & schedules | Jobs that fire only monthly or weekly |
Of these five, the classic failure is looking only at the code and feeling safe. When something is hardcoded in a config file or an environment variable, the string never appears in the code itself. When I audit, I look at config and environment variables with the same weight as code.
First, surface every hit mechanically
The first move is to pull the target model names from the whole repository. Two models are stopping, so search for both at once. Even "dead references" that linger only in comments or old docs should be surfaced first, then sorted.
# Surface references to the stopping models across code and config
grep -rnE "gemini-3\.1-flash-image-preview|gemini-3-pro-image-preview" \
--include="*.py" --include="*.ts" --include="*.js" \
--include="*.json" --include="*.yaml" --include="*.yml" \
--include="*.env*" . \
| tee /tmp/preview_model_hits.txt
echo "--- hit count ---"
wc -l < /tmp/preview_model_hits.txtDo not panic at a high count. What matters is not the count but whether each one is "a path that runs now." The next sort narrows it down to references that actually need work.
Sort the hits into three
Split the surfaced references by urgency. Deciding the criteria up front speeds up the judgment.
- Active: actually called by current requests. Replace first.
- Fallback / rare: does not run normally but fires under specific conditions. This is the most overlooked. Replace it too.
- Dead reference: comments, old docs, unreachable code. No replacement needed, but delete to avoid confusion.
Always replace active and fallback. In my experience, most shutdown incidents happen in the fallback branch. The complacency of "the top model is working, so we're fine" pushes inspection of the rarely-run path to later. Dead references do not affect behavior, but they become noise again next time someone audits, so clearing them now saves trouble later.
Replace with the successor, and consolidate into config
The replacement target is the successor image generation model corresponding to the stopping ones. Here I recommend one operational tweak. While you replace, stop hardcoding model names into the code and consolidate them in a single config point.
# model_config.py — consolidate the model name; eliminate hardcoding
# Future migrations then only change this one line
IMAGE_MODEL = os.environ.get("GEMINI_IMAGE_MODEL", "gemini-3-pro-image")
def generate_image(prompt: str):
return client.models.generate_content(
model=IMAGE_MODEL, # do not hardcode the model name at each call site
contents=prompt,
)Once consolidated, the next time a model migrates, the very act of searching the whole repository during an audit becomes unnecessary. Using this shutdown as a chance to lower future migration cost spares you from repeating the same work. Because I juggle several models in indie development, this consolidation has paid off at every migration.
After replacing, deliberately exercise the rare paths
The last part matters most. After replacing, deliberately fire the rare paths—fallbacks, monthly batches—without waiting for the production shutdown. The point is to find for yourself, before the cutoff, any spot you thought you replaced but did not.
# Final check that no reference to the stopping models remains
if grep -rqE "gemini-3\.1-flash-image-preview|gemini-3-pro-image-preview" \
--include="*.py" --include="*.ts" --include="*.js" \
--include="*.json" --include="*.yaml" --include="*.yml" .; then
echo "⚠️ References to the stopping models still remain"
else
echo "✅ Zero references to the stopping models"
fiA fallback branch does not run normally unless its condition is met, so in tests deliberately make the top model fail to force the path through. For a monthly batch, run it once by hand rather than waiting for the production trigger. Instead of confirming "it should work" on the shutdown day, confirm "it works" before the shutdown. That difference prevents silent failures on the rare paths.
A model shutdown with a deadline tempts you, in the rush, to fix only the active path and call it done. But oversights always remain on the path that is hard to see. Before the shutdown, search the whole repository for the target model names once. Start by sorting the hits into active, rare, and dead references, and you should reach June 25 quietly.