cd /news/developer-tools/announcing-the-google-gen-ai-sdk-for… · home topics developer-tools article
[ARTICLE · art-120605] src=cloud.google.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Announcing the Google Gen AI SDK for Kotlin 1.0: Idiomatic multiplatform access to Gemini

Google has released version 1.0 of the Google Gen AI SDK for Kotlin, a Kotlin Multiplatform library providing idiomatic access to Gemini models for JVM and Android developers. The SDK, available on Maven Central as com.google.genai:google-genai-kotlin:1.0.0, supports unary and streaming text generation, chat, and works with both the Gemini Developer API and the Gemini Enterprise Agent Platform.

read7 min views1 publishedSep 3, 2026

Integrating modern generative AI capabilities into Kotlin applications shouldn't require juggling raw HTTP clients or bridging disparate Java libraries. Today, we're excited to announce the 1.0 release of the Google Gen AI SDK for Kotlin (google-genai-kotlin

). You can dive right into the code, explore runnable samples, and star the project today on GitHub at googleapis/kotlin-genai

.

Built from the ground up as a Kotlin Multiplatform (KMP) library, the SDK brings idiomatic Kotlin paradigms (including first-class Coroutines, asynchronous Flow

streaming, and immutable data classes with named and default parameters) to developers targeting both the JVM (backend services, serverless functions, desktop) and Android.

The SDK provides a unified surface to interact with both the Gemini Developer API (Google AI Studio) and the Gemini Enterprise Agent Platform (on Google Cloud) with minimal configuration tweaks.

1. Getting started: Adding the dependency #

The SDK is published to Maven Central under com.google.genai:google-genai-kotlin

.

### Kotlin Multiplatform (KMP)

For multiplatform applications, add the dependency to your `commonMain`

source set:

  • code_block
  • <ListValue: [StructValue([('code', '// build.gradle.kts\r\nkotlin {\r\n sourceSets {\r\n commonMain.dependencies {\r\n implementation("com.google.genai:google-genai-kotlin:1.0.0")\r\n }\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563d00>)])]>

Standard JVM or Android projects

For single-platform Kotlin projects, Gradle automatically selects the optimal variant via Gradle Module Metadata:

  • code_block
  • <ListValue: [StructValue([('code', '// build.gradle.kts\r\ndependencies {\r\n implementation("com.google.genai:google-genai-kotlin:1.0.0")\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563670>)])]>

2. Unary and streaming text generation and chat #

The primary entry point is the Client

class. It manages HTTP connections and authentication automatically based on your environment variables (GEMINI_API_KEY

or GOOGLE_API_KEY

for Google AI Studio, and GOOGLE_GENAI_USE_ENTERPRISE=true with standard Google Cloud Application Default Credentials).

Single prompt request with Gemini Flash

Using Kotlin's use extension ensures the client's underlying network engine and HTTP connections are released cleanly:

  • code_block
  • <ListValue: [StructValue([('code', 'import com.google.genai.kotlin.Client\r\nimport kotlinx.coroutines.runBlocking\r\n\r\nfun main() = runBlocking {\r\n Client().use { client ->\r\n val response = client.models.generateContent(\r\n model = "gemini-flash-latest",\r\n text = "Explain quantum entanglement in two sentences."\r\n )\r\n\r\n println(response.text)\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec5631f0>)])]>

Low-latency streaming with Coroutines Flow

For interactive UIs and responsive CLI tools, generateContentStream returns a cold Kotlin Coroutine Flow<GenerateContentResponse>

, delivering token chunks in real time:

  • code_block
  • <ListValue: [StructValue([('code', 'import com.google.genai.kotlin.Client\r\nimport kotlinx.coroutines.runBlocking\r\n\r\nfun main() = runBlocking {\r\n Client().use { client ->\r\n val responseFlow = client.models.generateContentStream(\r\n model = "gemini-flash-latest",\r\n text = "Outline the key architectural patterns for microservices on Google Cloud."\r\n )\r\n\r\n responseFlow.collect { chunk ->\r\n chunk.text?.let { print(it) }\r\n }\r\n println()\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563040>)])]>

Multi-turn conversations (chat)

Managing conversation history manually across request turns can become tedious. The SDK includes a dedicated chats

service that automatically maintains context, appends turns, formats conversation history, and handles function calling:

  • code_block
  • <ListValue: [StructValue([('code', 'import com.google.genai.kotlin.Client\r\nimport com.google.genai.kotlin.types.Content\r\nimport com.google.genai.kotlin.types.GenerateContentConfig\r\nimport kotlinx.coroutines.runBlocking\r\n\r\nfun main() = runBlocking {\r\n Client().use { client ->\r\n val config = GenerateContentConfig(\r\n systemInstruction = Content.fromText("You are an expert Google Cloud Solutions Architect.")\r\n )\r\n\r\n // Create a multi-turn chat session\r\n val chat = client.chats.create(\r\n model = "gemini-flash-latest",\r\n config = config\r\n )\r\n\r\n // Turn 1\r\n val firstResponse = chat.sendMessage("We are designing an event-driven ingestion pipeline on Google Cloud.")\r\n println("Gemini: ${firstResponse.text}\n")\r\n\r\n // Turn 2: context from the first turn is included automatically\r\n val secondResponse = chat.sendMessage("Which managed messaging service should we choose: Pub/Sub or Kafka?")\r\n println("Gemini: ${secondResponse.text}\n")\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563cd0>)])]>

You can also use chat.sendMessageStream(...)

for streaming multi-turn chat responses.

Gemini's multimodal reasoning is especially effective when combined with external verification. For instance, when analyzing technical, medical, or scientific diagrams, you can attach Google Search Grounding to cross-check factual claims against live web sources.

  • code_block
  • <ListValue: [StructValue([('code', 'import com.google.genai.kotlin.Client\r\nimport com.google.genai.kotlin.types.*\r\nimport java.io.File\r\nimport kotlinx.coroutines.runBlocking\r\n\r\nfun main() = runBlocking {\r\n Client().use { client ->\r\n val imageBytes = File("src/main/resources/medical_diagram.png").readBytes()\r\n\r\n val content = Content(\r\n parts = listOf(\r\n Part(inlineData = Blob(mimeType = "image/png", data = imageBytes)),\r\n Part(text = "Is this anatomical diagram accurate? Verify labels against authoritative medical sources.")\r\n )\r\n )\r\n\r\n // Enable Google Search as a grounding tool\r\n val config = GenerateContentConfig(\r\n tools = listOf(Tool(googleSearch = GoogleSearch()))\r\n )\r\n\r\n val response = client.models.generateContent(\r\n model = "gemini-flash-latest",\r\n content = content,\r\n config = config\r\n )\r\n\r\n println("=== Analysis ===")\r\n println(response.text)\r\n\r\n // Inspect citations and search queries\r\n val grounding = response.groundingMetadata\r\n println("\n=== Search Queries Executed ===")\r\n grounding?.webSearchQueries?.forEach { println("- $it") }\r\n\r\n println("\n=== Grounding Sources ===")\r\n grounding?.groundingChunks?.mapNotNull { it.web }?.forEach { source ->\r\n println("- ${source.title}: ${source.uri}")\r\n }\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563ca0>)])]>

4. Visual generation and conversational editing: The Gemini 3 image family #

The SDK provides full support for Google's latest image generation models (popularly known as the Nano Banana series of models on leaderboards).

Generating and Saving an Image

Generated image bytes are delivered directly in the response parts as a Blob

:

  • code_block
  • <ListValue: [StructValue([('code', 'import com.google.genai.kotlin.Client\r\nimport java.io.File\r\nimport kotlinx.coroutines.runBlocking\r\n\r\nfun main() = runBlocking {\r\n Client().use { client ->\r\n val response = client.models.generateContent(\r\n model = "gemini-3.1-flash-image", // Nano Banana 2\r\n text = "A photorealistic blueprint of an eco-friendly modern datacenter, isometric view, 4k"\r\n )\r\n\r\n val imagePart = response.parts?.firstOrNull { it.inlineData != null }\r\n imagePart?.inlineData?.data?.let { bytes ->\r\n File("datacenter_blueprint.png").writeBytes(bytes)\r\n println("Image generated and saved successfully.")\r\n }\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec5637f0>)])]>

Conversational image-to-image editing

You can pass existing images and conversational edit instructions in the same request:

  • code_block
  • <ListValue: [StructValue([('code', 'val originalImage = File("input.png").readBytes()\r\n\r\nval editPrompt = Content(\r\n parts = listOf(\r\n Part(inlineData = Blob(mimeType = "image/png", data = originalImage)),\r\n Part(text = "Change the daylight illumination to a dramatic twilight skyline with illuminated windows.")\r\n )\r\n)\r\n\r\nval editResponse = client.models.generateContent(\r\n model = "gemini-3-pro-image", // Nano Banana Pro\r\n content = editPrompt\r\n)'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563640>)])]>

5. Real-time bidirectional interaction with Gemini Live #

For low-latency voice, audio, and live multimodal interactions, the SDK supports the Gemini Live API via persistent WebSocket connections using client.live.connect(...) :

  • code_block
  • <ListValue: [StructValue([('code', 'import com.google.genai.kotlin.Client\r\nimport com.google.genai.kotlin.types.AudioTranscriptionConfig\r\nimport com.google.genai.kotlin.types.LiveConnectConfig\r\nimport kotlinx.coroutines.launch\r\nimport kotlinx.coroutines.runBlocking\r\n\r\nfun main() = runBlocking {\r\n Client().use { client ->\r\n val model = if (client.enterprise) "gemini-live-2.5-flash-native-audio"\r\n else "gemini-3.1-flash-live-preview"\r\n\r\n val config = LiveConnectConfig(\r\n outputAudioTranscription = AudioTranscriptionConfig()\r\n )\r\n\r\n // Establish real-time bidirectional WebSocket session\r\n client.live.connect(model, config).use { session ->\r\n println("Connected to Gemini Live session!")\r\n\r\n // Launch collector for server messages (audio and text transcriptions)\r\n val receiveJob = launch {\r\n session.receive().collect { serverMessage ->\r\n serverMessage.serverContent?.outputTranscription?.text?.let { text ->\r\n print(text)\r\n }\r\n }\r\n }\r\n\r\n // Stream real-time text (or raw PCM audio blobs via session.sendRealtimeInput(audio = ...))\r\n session.sendRealtimeInput(text = "Hello Gemini! Give me a 5-second motivational quote.")\r\n\r\n // When finished, clean up\r\n receiveJob.cancel()\r\n session.closeSession()\r\n }\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaec563bb0>)])]>

6. Structured tool and function calling #

When building agentic workflows or bridging LLMs with backend microservices, developers can pass structured JSON schemas via FunctionDeclaration

. The model will intelligently select when to invoke the tool:

  • code_block
  • <ListValue: [StructValue([('code', 'val telemetryTool = FunctionDeclaration(\r\n name = "getDatacenterMetrics",\r\n description = "Fetch real-time CPU and thermal telemetry for a Google Cloud region",\r\n parameters = Schema(\r\n type = Type.OBJECT,\r\n properties = mapOf("region" to Schema(type = Type.STRING)),\r\n required = listOf("region")\r\n )\r\n)\r\n\r\nval response = client.models.generateContent(\r\n model = "gemini-flash-latest",\r\n text = "Check telemetry for europe-west1",\r\n config = GenerateContentConfig(\r\n tools = listOf(Tool(functionDeclarations = listOf(telemetryTool)))\r\n )\r\n)\r\n\r\nresponse.functionCalls?.firstOrNull()?.let { call ->\r\n println("Model triggered tool: ${call.name} with arguments: ${call.args}")\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaed15ebb0>)])]>

Additionally, when using the chats service, you can take advantage of Automatic Function Calling (AFC), which means that functions declared in the chat conversation can be invoked automatically and transparently by the SDK on your behalf, as you can see in the following example:

  • code_block
  • <ListValue: [StructValue([('code', 'fun main() = runBlocking {\r\n // A mocked function\r\n val getWeather = callableFunction("get_weather", paramName = "city") { city: String ->\r\n "18 degrees and sunny in $city"\r\n }\r\n\r\n Client().use { client ->\r\n val chat = client.chats.create(\r\n model = "gemini-flash-latest",\r\n automaticFunctionCalling = AutomaticFunctionCalling(getWeather),\r\n )\r\n\r\n // SDK calls get_weather if needed in this conversation\r\n println(chat.sendMessage("What is the weather in Zurich?").text)\r\n }\r\n}'), ('language', ''), ('caption', <wagtail.rich_text.RichText object at 0x7fbaed15ea30>)])]>

What's next? #

With the 1.0 release of the Google Gen AI SDK for Kotlin, Kotlin developers across backend server ecosystems (Ktor, Spring Boot, Quarkus, Micronaut) and mobile applications now have a clean, multiplatform foundation for building generative AI applications.

To learn more and get started, check out the following resources:

We look forward to seeing what you build with Kotlin and Gemini!

── more in #developer-tools 4 stories · sorted by recency
── more on @google 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/announcing-the-googl…] indexed:0 read:7min 2026-09-03 ·