← Code Recipes
Language Models

Google Gemini Free code examples in C#, Python, Java and JavaScript

Gemini models, natively multimodal — text, images, audio and video in one call.

C# Python Java JavaScript

WHAT THIS PAGE COVERS

Passing a PDF and an image into the same prompt without a preprocessing step.

Model gemini-flash-latest
Package google-genai
Checked

Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.

No official SDK — use the REST API

Google ships no first-party .NET Gen AI SDK. Community wrappers exist, but they all wrap this endpoint, and a wrapper you do not control is a dependency that can go unmaintained. HttpClient needs no package at all.

# Nothing to install — System.Net.Http.Json is in the shared framework.

setx GEMINI_API_KEY "..."
First call

The key goes in the x-goog-api-key header, never the query string — a URL ends up in proxy logs, browser history and error reports.

using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

const string Model = "gemini-flash-latest";

using HttpClient http = new()
{
    BaseAddress = new Uri("https://generativelanguage.googleapis.com/"),
};
http.DefaultRequestHeaders.Add(
    "x-goog-api-key", Environment.GetEnvironmentVariable("GEMINI_API_KEY"));

var request = new
{
    contents = new[]
    {
        new { parts = new[] { new { text = "Explain a database index in two sentences." } } },
    },
};

using var response = await http.PostAsJsonAsync(
    $"v1beta/models/{Model}:generateContent", request);

response.EnsureSuccessStatusCode();

using var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

string text = body.RootElement
    .GetProperty("candidates")[0]
    .GetProperty("content")
    .GetProperty("parts")[0]
    .GetProperty("text")
    .GetString()!;

Console.WriteLine(text);
Streaming

streamGenerateContent with alt=sse returns server-sent events. Read the stream line by line — buffering the whole response defeats the point.

using System.Text.Json;

var request = new
{
    contents = new[]
    {
        new { parts = new[] { new { text = "Write a haiku about indexes." } } },
    },
};

using var message = new HttpRequestMessage(
    HttpMethod.Post,
    $"v1beta/models/{Model}:streamGenerateContent?alt=sse")
{
    Content = JsonContent.Create(request),
};

using var response = await http.SendAsync(
    message, HttpCompletionOption.ResponseHeadersRead);

response.EnsureSuccessStatusCode();

using var reader = new StreamReader(await response.Content.ReadAsStreamAsync());

while (await reader.ReadLineAsync() is { } line)
{
    if (!line.StartsWith("data: ", StringComparison.Ordinal)) continue;

    using var chunk = JsonDocument.Parse(line["data: ".Length..]);

    if (chunk.RootElement.TryGetProperty("candidates", out var candidates) &&
        candidates[0].GetProperty("content")
            .TryGetProperty("parts", out var parts))
    {
        Console.Write(parts[0].GetProperty("text").GetString());
    }
}

Console.WriteLine();
Multimodal — text and an image in one call

inline_data takes base64 and the mime type. Anonymous objects serialise to the snake_case the API expects only if you name the properties exactly — inline_data, not inlineData.

using System.Net.Http.Json;
using System.Text.Json;

string imageBase64 = Convert.ToBase64String(
    await File.ReadAllBytesAsync("invoice.png"));

var request = new
{
    contents = new[]
    {
        new
        {
            parts = new object[]
            {
                new { text = "Extract the total and the due date as JSON." },
                new { inline_data = new { mime_type = "image/png", data = imageBase64 } },
            },
        },
    },
};

using var response = await http.PostAsJsonAsync(
    $"v1beta/models/{Model}:generateContent", request);

response.EnsureSuccessStatusCode();

using var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

Console.WriteLine(body.RootElement
    .GetProperty("candidates")[0]
    .GetProperty("content").GetProperty("parts")[0]
    .GetProperty("text").GetString());
Errors worth handling

Do not call EnsureSuccessStatusCode in production here — the response body carries the reason, and throwing it away leaves you with a status code and no idea why.

using System.Net;
using System.Text.Json;

using var response = await http.PostAsJsonAsync(
    $"v1beta/models/{Model}:generateContent", request);

if (!response.IsSuccessStatusCode)
{
    string detail = await response.Content.ReadAsStringAsync();

    Console.Error.WriteLine(response.StatusCode switch
    {
        HttpStatusCode.BadRequest   => $"Malformed request: {detail}",
        HttpStatusCode.Forbidden    => "GEMINI_API_KEY missing, revoked, or lacking access.",
        HttpStatusCode.NotFound     => "Unknown model id — check the official docs linked below.",
        HttpStatusCode.TooManyRequests => "Rate limited — retry after a backoff.",
        _ => $"API error {(int)response.StatusCode}: {detail}",
    });
    return;
}

using var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
var candidate = body.RootElement.GetProperty("candidates")[0];

// A blocked answer is HTTP 200 with no parts — check before reading text.
if (candidate.TryGetProperty("finishReason", out var finish) &&
    finish.GetString() is not "STOP")
{
    Console.Error.WriteLine($"Incomplete: {finish.GetString()}");
}
Install

google-genai is the current SDK. If you find google-generativeai in a tutorial, that is the previous one — the import path and the client shape both changed.

pip install google-genai

export GEMINI_API_KEY="..."      # macOS / Linux
setx GEMINI_API_KEY "..."        # Windows, then open a new shell
First call

The client picks up GEMINI_API_KEY (or GOOGLE_API_KEY) on its own. response.text concatenates every text part, so there is no block loop to write.

from google import genai

client = genai.Client()

response = client.models.generate_content(
    model="gemini-flash-latest",
    contents="Explain a database index in two sentences.",
)

print(response.text)
print(response.usage_metadata.prompt_token_count,
      response.usage_metadata.candidates_token_count)
Streaming

A separate method, not a flag. Some chunks carry no text — a safety block or a tool call — so guard before writing.

for chunk in client.models.generate_content_stream(
    model="gemini-flash-latest",
    contents="Write a haiku about indexes.",
):
    if chunk.text:
        print(chunk.text, end="", flush=True)

print()
Multimodal — text, image and PDF in one call

No OCR step, no separate vision endpoint. Mix parts freely in contents: a prompt, an image, a document. For anything over about 20 MB, upload it first with client.files.upload and pass the handle.

from google import genai
from google.genai import types

client = genai.Client()

with open("invoice.png", "rb") as f:
    image_bytes = f.read()

response = client.models.generate_content(
    model="gemini-flash-latest",
    contents=[
        "Extract the total and the due date as JSON.",
        types.Part.from_bytes(data=image_bytes, mime_type="image/png"),
    ],
)
print(response.text)

# Large or reused files: upload once, reference by handle.
handbook = client.files.upload(file="handbook.pdf")
summary = client.models.generate_content(
    model="gemini-flash-latest",
    contents=["Summarise the leave policy.", handbook],
)
print(summary.text)
Tool calling — the automatic kind

Pass the Python function itself and the SDK generates the schema from the signature and docstring, calls it, and feeds the result back. No loop to write. Pass a declaration instead when you need to run the call yourself.

from google.genai import types

def get_weather(city: str) -> str:
    # The docstring and type hints BECOME the schema the model sees.
    # A vague description here is the usual reason a tool is never called.
    # Args:
    #     city: City name, e.g. Delhi.
    return "29C, clear"

response = client.models.generate_content(
    model="gemini-flash-latest",
    contents="What is the weather in Delhi?",
    config=types.GenerateContentConfig(tools=[get_weather]),
)

print(response.text)
Errors worth handling

Gemini returns a finish_reason on the candidate. SAFETY means the answer was blocked, and response.text will be empty rather than raising — check before you print it.

from google.genai import errors

try:
    response = client.models.generate_content(
        model="gemini-flash-latest",
        contents="...",
    )
except errors.ClientError as e:
    # 400 bad request, 403 key problem, 404 unknown model, 429 rate limit
    raise SystemExit(f"Request rejected ({e.code}): {e.message}")
except errors.ServerError as e:
    raise SystemExit(f"Server error ({e.code}) — safe to retry: {e.message}")

candidate = response.candidates[0]
if candidate.finish_reason and candidate.finish_reason.name != "STOP":
    print("Incomplete:", candidate.finish_reason.name)   # SAFETY, MAX_TOKENS, ...
else:
    print(response.text)
Install

The official Google Gen AI SDK for Java. Gradle: implementation("com.google.genai:google-genai:1.73.0").

<dependency>
    <groupId>com.google.genai</groupId>
    <artifactId>google-genai</artifactId>
    <version>1.73.0</version>
</dependency>
First call

The no-argument constructor reads GOOGLE_API_KEY from the environment — note the name: the Java SDK uses GOOGLE_API_KEY where Python also accepts GEMINI_API_KEY. The third argument is the config, which may be null.

import com.google.genai.Client;
import com.google.genai.types.GenerateContentResponse;

// Reads GOOGLE_API_KEY. Or: Client.builder().apiKey(key).build()
Client client = new Client();

GenerateContentResponse response = client.models.generateContent(
    "gemini-flash-latest",
    "Explain a database index in two sentences.",
    null);

System.out.println(response.text());
Streaming

ResponseStream is closeable and holds an HTTP connection. Close it, or the pool stalls under load.

import com.google.genai.ResponseStream;
import com.google.genai.types.GenerateContentResponse;

try (ResponseStream<GenerateContentResponse> stream =
         client.models.generateContentStream(
             "gemini-flash-latest",
             "Write a haiku about indexes.",
             null)) {

    for (GenerateContentResponse chunk : stream) {
        System.out.print(chunk.text());
    }
}

System.out.println();
Multimodal — text and an image in one call

Part.fromBytes takes the raw bytes and a mime type. No OCR step and no separate vision endpoint.

import com.google.genai.types.Content;
import com.google.genai.types.GenerateContentResponse;
import com.google.genai.types.Part;

import java.nio.file.Files;
import java.nio.file.Path;

byte[] image = Files.readAllBytes(Path.of("invoice.png"));

Content content = Content.fromParts(
    Part.fromText("Extract the total and the due date as JSON."),
    Part.fromBytes(image, "image/png"));

GenerateContentResponse response = client.models.generateContent(
    "gemini-flash-latest", content, null);

System.out.println(response.text());
Errors worth handling

A blocked answer is not an exception — the response simply carries no text. Check the finish reason before printing.

import com.google.genai.errors.ClientException;
import com.google.genai.errors.ServerException;
import com.google.genai.types.GenerateContentResponse;

try {
    GenerateContentResponse response = client.models.generateContent(
        "gemini-flash-latest", "...", null);

    response.candidates().ifPresent(candidates -> candidates.stream()
        .findFirst()
        .flatMap(candidate -> candidate.finishReason())
        .ifPresent(reason -> {
            if (!"STOP".equals(reason.toString())) {
                System.err.println("Incomplete: " + reason);
            }
        }));

    System.out.println(response.text());
} catch (ClientException e) {
    // 400 malformed, 403 key problem, 404 unknown model, 429 rate limited
    System.err.println("Request rejected: " + e.getMessage());
} catch (ServerException e) {
    System.err.println("Server error — safe to retry: " + e.getMessage());
}
Install

@google/genai is the current SDK. @google/generative-ai is the previous one — different import, different client.

npm install @google/genai

export GEMINI_API_KEY="..."
First call

Pass the key explicitly here: the Node client does not read the environment on its own the way the Python one does.

import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const response = await ai.models.generateContent({
  model: "gemini-flash-latest",
  contents: "Explain a database index in two sentences.",
});

console.log(response.text);
console.log(response.usageMetadata.promptTokenCount,
            response.usageMetadata.candidatesTokenCount);
Streaming

A separate method, and it returns an async iterable. Some chunks carry no text, so guard before writing.

const stream = await ai.models.generateContentStream({
  model: "gemini-flash-latest",
  contents: "Write a haiku about indexes.",
});

for await (const chunk of stream) {
  if (chunk.text) process.stdout.write(chunk.text);
}
Multimodal — text and an image in one call

inlineData takes base64. No OCR step and no separate vision endpoint — the image is just another part of the prompt.

import { GoogleGenAI } from "@google/genai";
import fs from "node:fs";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const imageBase64 = fs.readFileSync("invoice.png", { encoding: "base64" });

const response = await ai.models.generateContent({
  model: "gemini-flash-latest",
  contents: [
    { text: "Extract the total and the due date as JSON." },
    { inlineData: { mimeType: "image/png", data: imageBase64 } },
  ],
});

console.log(response.text);
Tool calling

Declare the function, read response.functionCalls, run it yourself, then send the result back as a functionResponse part. The model has produced no answer until that second call.

import { Type } from "@google/genai";

const getWeather = {
  name: "get_weather",
  description: "Current weather for a city.",
  parameters: {
    type: Type.OBJECT,
    properties: { city: { type: Type.STRING } },
    required: ["city"],
  },
};

const contents = [
  { role: "user", parts: [{ text: "What is the weather in Delhi?" }] },
];

const first = await ai.models.generateContent({
  model: "gemini-flash-latest",
  contents,
  config: { tools: [{ functionDeclarations: [getWeather] }] },
});

for (const call of first.functionCalls ?? []) {
  contents.push({ role: "model", parts: [{ functionCall: call }] });
  contents.push({
    role: "user",
    parts: [{
      functionResponse: {
        name: call.name,
        response: { celsius: 29, sky: "clear" },
      },
    }],
  });
}

const second = await ai.models.generateContent({
  model: "gemini-flash-latest",
  contents,
  config: { tools: [{ functionDeclarations: [getWeather] }] },
});
console.log(second.text);
Errors worth handling

A blocked answer is not an exception: finishReason comes back as SAFETY and response.text is empty. Check it before displaying anything.

try {
  const response = await ai.models.generateContent({
    model: "gemini-flash-latest",
    contents: "...",
  });

  const finish = response.candidates?.[0]?.finishReason;
  if (finish && finish !== "STOP") {
    console.warn("Incomplete:", finish);   // SAFETY, MAX_TOKENS, ...
  } else {
    console.log(response.text);
  }
} catch (error) {
  // The SDK throws with a status for 400 / 403 / 404 / 429.
  console.error(`Request failed (${error.status ?? "?"}): ${error.message}`);
}

QUESTIONS

Which languages are the Google Gemini examples in?

C#, Python, Java and JavaScript. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.

Which package do I install for Google Gemini?

The samples use google-genai. The install step on each language tab gives the exact command.

Which Google Gemini model do these examples use?

gemini-flash-latest, checked against the official documentation on 25 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.

Where is the official Google Gemini documentation?

https://ai.google.dev/gemini-api/docs — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.

ALSO IN LANGUAGE MODELS

The authority

Official Google Gemini documentation

Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.

Read the docs ↗

https://ai.google.dev/gemini-api/docs

New drops, every week

Free tools & Claude templates, landing regularly.

We keep shipping new free tools, code recipes and Claude Code templates. Follow @freeyantra on Instagram or join the newsletter so you never miss one.

Follow @freeyantra

or get them by email

Double opt-in. Unsubscribe any time. Privacy