Gemini AI Basic

Used in this guide:
Next.js 16.0.1
google/genai 1.29.0

Introduction

This guide walks you through the basic setup for integrating Google Gemini AI into a Next.js project using the official @google/genai SDK. You’ll learn how to install the package, set up your API key securely with environment variables, create a simple API route to handle Gemini requests, and build a basic front-end page to send prompts and display AI responses.


1. Install Google GenAI SDK

npm install @google/genai


API Key Setup

Get your API Key at Google AI Studio

Click create API Key. Note that you can also create a project at the same time. I'll use the below values for my test project:

  • project name: test-gemini-01
  • api key name: test-gemini-01

Store API Key in a Environment Variable

root/.env.local
GEMINI_API_KEY=_your_api_key_


3. Create Gemini API Route

app/api/gemini/route.ts
import { GoogleGenAI } from "@google/genai";
import { NextRequest, NextResponse } from "next/server";
 
// Create GoogleGenAI Client
const genAI = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY
});
 
export async function POST(req: NextRequest) {
 
    try {
        const { prompt } = await req.json() as { prompt: string };
        if (!prompt) {
            return NextResponse.json({ error: "Missing 'prompt' in request body."}, { status: 400 })
        }
        const res = await genAI.models.generateContent({
            model: "gemini-2.5-flash",
            contents: prompt,
        });
 
        const output = res.text;
        return NextResponse.json({ output });
 
    } catch (error) {
        console.error("Gemini API Error:", (error as Error).message);
        return NextResponse.json({ error: "Failed to generate content."}, { status: 500 });
    }
 
}


4. Use in a Next.js Page

app/(pages)/gemini-example/page.tsx
"use client"
import { useState } from "react"
 
export default function GeminiExamplePage() {
 
    const [prompt, setPrompt] = useState("");
    const [response, setResponse] = useState('Type a prompt and click "Generate" to ask Gemini AI.');
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("");
 
    const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
 
        if (!prompt.trim()) {
            setError("Please enter a prompt first.");
            return;
        }
 
        setIsLoading(true);
 
        try {
            const res = await fetch('/api/gemini', {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({ prompt }),
            });
 
            const data = await res.json();
 
            if (!res.ok || data.error) {
                setError(data.error || `Error: Status ${res.status}`);
                setResponse("Failed to get a response from Gemini.");
            };
 
            setResponse(data.output);
 
        } catch (error) {
            console.error("Fetch error: ", error);
            setError("Error: A network error occurred. Check your connection or server status.");
            setResponse("Failed to connect to Gemini.");
        } finally {
            setIsLoading(false);
        }
    }
 
    return (
        <div className="flex flex-col gap-4 w-full max-w-2xl p-8">
            <div className="">
                <h1 className="font-bold text-md">Gemini API Example</h1>
                <p className="text-sm text-gray-400">This page calls your secure Next.js API Route which then talks to the Gemini API.</p>
            </div>
            <form onSubmit={handleSubmit}>
                <textarea
                    placeholder="Ask Gemini anything..."
                    value={prompt}
                    rows={4}
                    disabled={isLoading}
                    onChange={(e) => setPrompt(e.target.value)}
                    className="bg-gray-700 rounded-lg w-full p-4 text-sm"
                />
                <div className="flex w-full justify-end">
                    <button
                        type="submit"
                        disabled={isLoading}
                        className="bg-sky-600 py-2 px-4 rounded-md text-sm cursor-pointer"
                    >
                        {isLoading ? "Generating response...": "Submit"}
                    </button>
                </div>
            </form>
 
            {error && (
                <div className="text-amber-500">
                    <p>{error}</p>
                </div>
            )}
 
            <div className="space-y-4 text-sm">
                <h2>Gemini AI Response</h2>
                {isLoading && !response.startsWith("Type a prompt") ? (
                    <p>Thinking...</p>
                ) : (
                    <div className="border border-gray-700 rounded-lg p-4 leading-8">
                        <p>{response}</p>
                    </div>
                )}
            </div>
 
        </div>
    )
}

JKT

Stay focused, and the rest will follow

©Jakkrit Turner. All rights reserved