GEMINI LABJP
SUNSET — Six days until the image generation models shut down: the imagen-4.0 family and Gemini 3 Image models stop on August 17MIGRATE — gemini-3.1-flash-image is the recommended replacement, and it means rewriting generate_images calls as generate_contentCHECK — The same prompt will not necessarily produce the same picture after migrating, so secure any images you still need before the cutoffCLASSROOM — August 17 is also the day Gemini in Classroom arrives on mobile; the web rollout to students of all ages began on August 10DEPRECATION — The Grok 4.1 family shuts down on August 20, and gemini-robotics-er-1.6-preview on August 31, succeeded by the er-2 modelsCHANGELOG — The Gemini API changelog still ends at July 30. The most recent major change remains the GA of Gemini 3.6 Flash and 3.5 Flash-LiteSUNSET — Six days until the image generation models shut down: the imagen-4.0 family and Gemini 3 Image models stop on August 17MIGRATE — gemini-3.1-flash-image is the recommended replacement, and it means rewriting generate_images calls as generate_contentCHECK — The same prompt will not necessarily produce the same picture after migrating, so secure any images you still need before the cutoffCLASSROOM — August 17 is also the day Gemini in Classroom arrives on mobile; the web rollout to students of all ages began on August 10DEPRECATION — The Grok 4.1 family shuts down on August 20, and gemini-robotics-er-1.6-preview on August 31, succeeded by the er-2 modelsCHANGELOG — The Gemini API changelog still ends at July 30. The most recent major change remains the GA of Gemini 3.6 Flash and 3.5 Flash-Lite
Articles/Dev Tools
Dev Tools/2026-03-30Advanced

Firebase Genkit × Gemini API in Production — Design Choices and Gotchas from a Month of Indie Backend Work

Field notes from a month of running Firebase Genkit and Gemini API behind an indie app review-summarization backend. Flow and Tool design, Cloud Functions vs. Cloud Run, real cost and latency numbers, and seven undocumented gotchas.

Firebase Genkit2Gemini API208RAG14Cloud FunctionsCloud Run5Agents8Production33AI Development4

Premium Article

I started wiring Firebase Genkit into the back end of my indie apps in early 2026. The first thing I shipped was a small Flow that summarized user reviews into a dashboard. That alone replaced about eighty lines of Cloud Functions code I had been maintaining for two years — the usual "call Gemini, watch the token budget, format the result, log to Firestore" routine — with a single defineFlow call. I sat at my desk for a while just looking at the diff.

When you run an indie backend, evaluation collapses into two questions: how many seconds does the user wait, and what does the invoice say at the end of the month. On apps funded by ad revenue, both of those land directly on the bottom line. So when I looked at Genkit, I skipped the feature list and watched only those two numbers.

What follows is the notebook from running that review-summarization Flow in production for a month. It covers the fundamentals — Flow design, Tool composition, RAG, deployment, security — and then the parts the docs do not warn you about: where it actually hurts, and what the real cost and latency numbers looked like.

One caveat up front. The measurements were taken in April 2026. The model lineup has turned over since, and the same word "Flash" now carries a very different unit price. Carrying those dollar figures around unchanged will trip you up, so there is a later section on how to re-derive them.

Understanding Firebase Genkit: Core Concepts and Advantages

Firebase Genkit consolidates the fragmented landscape of LLM integration patterns into a unified abstraction called the Flow. Rather than juggling PromptTemplate classes, Chain objects, and Agent frameworks from different libraries, Genkit provides a consistent mental model that scales from simple text generation to complex multi-step autonomous systems.

The Three Core Abstractions

Flows are the fundamental unit of AI computation. Each Flow has:

  • Type-safe inputs and outputs: Defined via Zod schemas, ensuring compile-time correctness and IDE autocomplete support
  • Built-in streaming: Native support for real-time response streaming, critical for modern UX where users expect immediate feedback
  • Automatic tracing: Every API call, intermediate result, and error is captured automatically, transforming production debugging from guesswork into forensic analysis
  • Composability: Flows can call other Flows, enabling modular architecture and code reuse

Tools are discrete actions that Flows invoke—API calls, database queries, file system operations. Gemini's built-in tool calling capability means the model itself decides which Tools to use and in what sequence, creating truly autonomous behavior.

Prompts are templated instructions with variable injection. They're more than simple strings; they're structured definitions that can include system instructions, few-shot examples, and contextual information formatted for optimal model understanding.

Embedders and Retrievers form the foundation of RAG systems. Embedders convert text to dense vectors, while Retrievers perform similarity searches across your knowledge base, augmenting the model's input with relevant context.

Initial Setup: Integrating with Gemini 2.5 Pro and Flash

Getting Genkit running with Gemini requires minimal boilerplate:

# Requires Node.js 18+
npm init -y
npm install firebase-genkit @genkit-ai/gemini

Core initialization:

// genkit.ts
import { genkit } from 'genkit';
import { googleAI } from '@genkit-ai/googleai';
 
// Keep model IDs in one place so they can be swapped via environment
export const MODELS = {
  pro:   googleAI.model(process.env.GEMINI_PRO_MODEL   ?? 'gemini-2.5-pro'),
  flash: googleAI.model(process.env.GEMINI_FLASH_MODEL ?? 'gemini-2.5-flash'),
} as const;
 
const ai = genkit({
  plugins: [googleAI({ apiKey: process.env.GEMINI_API_KEY })],
  model: MODELS.pro,  // Default model for all operations
});
 
export default ai;

Keep Model IDs in One Place

I started out importing the model constants the plugin exports directly into every Flow. It works, but swapping models then means editing one import line per Flow. Once I passed twenty Flows, more of my time went into checking "is this the one Flow still pinned to the old model?" than into writing the Flows.

Now everything funnels through a single MODELS object, with the actual IDs coming from environment variables. Pointing staging at a newer model no longer requires a code change, and when it comes time to recompute costs — the section further down — I can see which Flow used which ID by reading one file.

Every code sample below assumes this MODELS object is imported.

Configuration best practices:

Always externalize API keys via environment variables. In production, use Google Cloud Secret Manager. For local development, use a .env.local file. Never hardcode credentials or use real key formats like AIzaSy.... Instead, use placeholder values like YOUR_GEMINI_API_KEY when documenting examples.

// Multi-environment configuration
const getApiKey = () => {
  if (process.env.ENVIRONMENT === 'production') {
    return process.env.GEMINI_API_KEY; // From Secret Manager
  }
  return process.env.LOCAL_GEMINI_KEY; // From .env.local
};
 
if (!getApiKey()) {
  throw new Error('GEMINI_API_KEY not configured');
}

The split is straightforward on paper: Pro for reasoning depth, Flash for latency and unit price.

What does not hold is the assumption that this relationship survives a generation change. As the numbers later in this article show, 3.x-series Flash models are priced well above 2.5-series Flash. If your code carries the assumption "anything called Flash is cheap," the surprise arrives on the invoice the month after you upgrade. Treat the model name as a signal about capability, not about price.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
One month of real cost, latency, and p95 numbers from a Gemini 2.5 Flash review-summarization Flow running on a single indie iOS/Android app
Seven gotchas the official docs do not mention (35–45s cold starts, concurrency defaulting to 1, double-counted runFlow traces, Secret Manager billing, Flow rename breaking dashboards, PII in traces, streamCallback back-pressure)
Cloud Functions vs. Cloud Run decision matrix, plus a small pricing module that lets you re-derive monthly cost after the model lineup turns over
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Dev Tools2026-07-09
Closing the Failures That Never Throw: Normalizing Gemini API Responses into a Discriminated Union
An HTTP 200 with an empty body will never reach your catch block. Here is how I normalize finishReason and blockReason into a discriminated union, and let a never check turn missed cases into compile errors.
Dev Tools2026-05-24
Running Streamlit + Gemini as a Production BI Dashboard — Auth, Cost, Caching, Rate Limits, Observability
A design memo for promoting a Streamlit + Gemini data analysis app into a real multi-user internal BI dashboard — authentication, cost optimization, result caching, per-user rate limits, and observability, all from production experience.
Dev Tools2026-04-22
Async AI Job Queues with Gemini API and Cloud Tasks — Production Patterns for Timeouts, Retries, and Rate Limits
Migrate synchronous Cloud Run + Gemini calls to a Cloud Tasks async job queue. Covers retries, DLQ, idempotent workers, and cost modeling with working code.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →