GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/API / SDK
API / SDK/2026-05-16Intermediate

Debugging Gemini API Calls from Next.js App Router Server Actions

Practical solutions for the most common errors when calling Gemini API from Next.js App Router Server Actions: undefined env vars, broken streaming, and deploy-only failures.

Gemini API192Next.js2Server ActionsApp Routertroubleshooting82

This site (gemilab.net) runs on Next.js App Router, which means Gemini API integration in Server Actions is something I deal with regularly. I've been building and shipping independent apps since 2013 — with over 50 million cumulative downloads across my app portfolio — and one constant across every stack is this: the faster you can narrow down a deployment-only bug, the more time you have for the actual work.

Here's a rundown of the specific error patterns I've run into as indie developer Masaki Hirokawa when calling Gemini API from Next.js Server Actions, along with the fixes that actually worked.

Error 1: Environment Variable Returns undefined in Server Actions

This is the most common confusion, and the fix is almost always the same.

Server Actions run server-side only. That means you don't need — and shouldn't use — the NEXT_PUBLIC_ prefix on your Gemini API key. The problem arises when developers set NEXT_PUBLIC_GEMINI_API_KEY thinking they need it both client and server-side. It technically works, but it exposes your API key in the client bundle.

// ❌ Works, but leaks your API key to the client bundle
'use server'
import { GoogleGenerativeAI } from '@google/generative-ai'
 
const genAI = new GoogleGenerativeAI(process.env.NEXT_PUBLIC_GEMINI_API_KEY ?? '')
 
// ✅ Server-only variable — no NEXT_PUBLIC_ prefix
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')

Keep .env.local clean:

# Server-only — Server Actions and Route Handlers
GEMINI_API_KEY=YOUR_API_KEY_HERE
 
# Client-accessible — non-sensitive values only
NEXT_PUBLIC_SITE_NAME=My App

On Vercel, .env.local is not deployed automatically. If the error only appears after deployment, check that GEMINI_API_KEY is configured in the Vercel dashboard under Settings → Environment Variables. Across the multiple services I run in parallel, keeping staging and production environment variables separated from day one has saved me more than a few last-minute surprises.

Error 2: Streaming Doesn't Work from Server Actions

"I'm trying to use generateContentStream but it doesn't work in a Server Action" — this comes up constantly.

The underlying reason: Server Actions can only return JSON-serializable values. An AsyncGenerator or ReadableStream can't be serialized, so returning one directly causes either a type error or a silent runtime failure.

// ❌ Broken — AsyncGenerator is not serializable
'use server'
 
export async function generateWithStream(prompt: string) {
  const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' })
  const result = await model.generateContentStream(prompt)
  return result.stream // This fails at runtime
}

Two fixes work here.

Fix A: Use a Route Handler for streaming

Route Handlers handle streaming cleanly:

// app/api/generate/route.ts
import { GoogleGenerativeAI } from '@google/generative-ai'
import { NextRequest } from 'next/server'
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')
 
export async function POST(req: NextRequest) {
  const { prompt } = await req.json()
  const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' })
  const result = await model.generateContentStream(prompt)
 
  const stream = new ReadableStream({
    async start(controller) {
      for await (const chunk of result.stream) {
        controller.enqueue(new TextEncoder().encode(chunk.text()))
      }
      controller.close()
    },
  })
 
  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  })
}

Fix B: Use Vercel AI SDK's createStreamableValue

If you're already on the Vercel AI SDK, createStreamableValue wraps async generators into a serializable format that works with Server Actions:

'use server'
import { createStreamableValue } from 'ai/rsc'
import { GoogleGenerativeAI } from '@google/generative-ai'
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')
 
export async function generateText(prompt: string) {
  const stream = createStreamableValue('')
  const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' })
 
  ;(async () => {
    const result = await model.generateContentStream(prompt)
    for await (const chunk of result.stream) {
      stream.update(chunk.text())
    }
    stream.done()
  })()
 
  return { output: stream.value }
}

My default is to keep Gemini streaming in Route Handlers. It's simpler, easier to debug in production logs, and doesn't require pulling in the AI SDK.

Error 3: Internal Server Error on Deploy Only, Not Locally

This is the hardest to debug because it only surfaces after deployment. Three root causes cover most cases.

Cause A: SDK initialized at module level

When GoogleGenerativeAI is instantiated at the top of the file, it runs during module evaluation — before environment variables are guaranteed to be loaded:

// ❌ Risky: runs at module load time
import { GoogleGenerativeAI } from '@google/generative-ai'
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!)
 
export async function myAction(input: string) { ... }
 
// ✅ Safe: move initialization inside the function
export async function myAction(input: string) {
  const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')
  // ...
}

Cause B: Serverless function timeout (Vercel)

On Vercel's free plan, functions time out after 10 seconds. Long Gemini prompts or large context windows can hit this. Set maxDuration in your Route Handler:

// Next.js 14.2+
export const maxDuration = 60 // seconds (requires Vercel Pro above 10)

Cause C: Edge Runtime incompatibility

If your file has export const runtime = 'edge', the @google/generative-ai package will fail because it depends on Node.js APIs unavailable in Edge Runtime:

// ❌ Breaks Gemini API
export const runtime = 'edge'
 
// ✅ Remove it, or explicitly specify Node.js
export const runtime = 'nodejs'

When to Use Server Actions vs Route Handlers

Running multiple projects simultaneously as an indie developer, here's the split I default to:

Use Server Actions for:

  • Form submissions that trigger Gemini API calls
  • One-shot generation tied to a user action (button click → generate → save to DB)
  • Anything where you want Next.js to manage caching and revalidation automatically

Use Route Handlers for:

  • Streaming responses from Gemini API to the client
  • Endpoints consumed by external services or webhooks
  • Shared API endpoints across multiple parts of the app

Locking in this split early prevents painful refactors later.

Debugging Checklist

When a Gemini API call breaks only in production:

  1. Check Vercel build logs — environment variable errors often surface here before runtime
  2. Check the Functions tab in Vercel for timeout duration and execution time
  3. Run next start locally (not next dev) to reproduce production-like behavior
  4. Add console.error inside the Server Action and check Vercel's runtime logs

The gap between next dev and production is larger than it looks. Running next start before every deploy that touches Gemini API integration will catch most surprises before they hit users.

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 →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API / SDK2026-06-22
Gemini API on Google Cloud: Diagnosing Production Errors Layer by Layer
Systematically diagnose Gemini API errors in Google Cloud production environments. Covers IAM permissions, Vertex AI vs AI Studio, VPC Service Controls, quota management, service accounts, and multi-region failover with full code examples.
API / SDK2026-06-21
How to Handle Gemini API Model Deprecation and Migration Errors
A practical guide to migrating from deprecated Gemini API models and resolving common migration errors.
API / SDK2026-06-03
Gemini Live API Audio Sounds Sped Up — Fixing the Sample Rate Mismatch
When Gemini Live API responses sound high-pitched and sped up, or come back full of noise, the cause is almost always that the 24kHz output is being played at a different sample rate. Here are the concrete fixes for both the browser and iOS.
📚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 →