Imagen 3 & 4 Shut Down June 24: Migrate to Gemini Image (2026) Google is shutting down all Imagen models on Firebase AI Logic on June 24, 2026, and on Vertex AI on August 17, 2026, requiring developers to migrate to the Gemini Image model (gemini-2.5-flash-image). The migration involves renaming the API method from generate_images to generate_content, updating the model identifier, and restructuring the response, with mask-based editing (inpainting, outpainting, object removal) having no replacement and a separate deadline of June 30, 2026. June 24, 2026. That is the shutdown date for every Imagen model on Firebase AI Logic — imagen-3.0-generate-002 , imagen-4.0-generate-001 , imagen-4.0-ultra-generate-001 , imagen-4.0-fast-generate-001 . All of them. If you have been putting off this migration, you have run out of runway. The replacement is Google's Gemini Image models — internally called "Nano Banana," publicly named gemini-2.5-flash-image . The migration is mostly a one-function rename and a response structure update, around 90 minutes of work for most codebases. The catch: one Imagen capability, mask-based editing, has no replacement at all. That separate deadline hits June 30. Firebase AI Logic's migration documentation confirms these shutdown dates: imagen-3.0-generate-002 — June 24, 2026 imagen-4.0-generate-001 — June 24, 2026 imagen-4.0-ultra-generate-001 — June 24, 2026 imagen-4.0-fast-generate-001 — June 24, 2026 imagen-3.0-capability-001 mask editing: inpainting, outpainting, object removal — June 30, 2026 Vertex AI runs on a slightly different clock — Google recommends migrating before June 30, with a hard shutdown date of August 17 for Vertex AI users on legacy Imagen endpoints. Firebase AI Logic is the shorter deadline. Don't assume extra time if your app uses the Firebase SDK. Three things change simultaneously: the method name, the model identifier, and the response structure. All three break if you miss any one of them. Before Imagen : python import google.generativeai as genai client = genai.Client api key="YOUR KEY" response = client.models.generate images model="imagen-4.0-generate-001", prompt="A red fox running through snow", config={"number of images": 1, "output mime type": "image/jpeg"} image bytes = response.generated images 0 .image.image bytes After Gemini Image : python import google.generativeai as genai client = genai.Client api key="YOUR KEY" response = client.models.generate content model="gemini-2.5-flash-image", contents="A red fox running through snow" image bytes = response.candidates 0 .content.parts 0 .inline data.data generate images becomes generate content . The response path shifts from .generated images 0 .image.image bytes to .candidates 0 .content.parts 0 .inline data.data . The config dict drops entirely — gemini-2.5-flash-image does not accept number of images as a parameter. If you need multiple images, call the API multiple times. The response structure change is where most migration bugs land. Imagen returned a typed ImageGenerationResponse with a strongly-typed .images array. Gemini Image returns a GenerateContentResponse with a mixed .parts array. If your call generates both text and an image in the same response Gemini Image supports this; Imagen did not , you cannot reliably grab index 0 — you need to filter parts by type. js // Before const response = await ai.models.generateImages { model: 'imagen-4.0-generate-001', prompt: 'A red fox running through snow', config: { numberOfImages: 1, outputMimeType: 'image/jpeg' } } ; const imageBytes = response.generatedImages 0 .image.imageBytes; // After const response = await ai.models.generateContent { model: 'gemini-2.5-flash-image', contents: 'A red fox running through snow' } ; const imageBytes = response.candidates 0 .content.parts 0 .inlineData.data; Same pattern: method rename, model name, response path. The camelCase shifts to match — inlineData rather than inline data in the JavaScript SDK. Watch for that. Mobile developers using Firebase AI Logic have platform-specific SDK changes on top of the model swap. Swift — Before: js let imagenModel = FirebaseAI.imagenModel modelName: "imagen-4.0-generate-001" let response = try await imagenModel.generateImages from: "A red fox in snow" let imageData = response.images.first?.data Swift — After: js let geminiModel = FirebaseAI.generativeModel modelName: "gemini-2.5-flash-image" let response = try await geminiModel.generateContent "A red fox in snow" let imageData = response.candidates.first?.content.parts .compactMap { $0 as? InlineDataPart } .first?.data Kotlin — Before: val imagenModel = Firebase.ai.imagenModel "imagen-4.0-generate-001" val response = imagenModel.generateImages "A red fox in snow" val imageData = response.images.firstOrNull ?.data Kotlin — After: val geminiModel = Firebase.ai.generativeModel "gemini-2.5-flash-image" val response = geminiModel.generateContent "A red fox in snow" val imageData = response.candidates.firstOrNull ?.content?.parts ?.filterIsInstance ?.firstOrNull ?.inlineData?.data The Swift version uses .compactMap { $0 as? InlineDataPart } to filter the parts array. Kotlin uses filterIsInstance