Building AI-Powered Flutter Apps with Gemini
Generative AI can be integrated into Flutter applications for chat, summarization, classification, content generation, document processing, and intelligent assistants.
A production application should avoid putting sensitive API credentials directly in the mobile application.
A safer architecture is:
Flutter App
|
| HTTPS
v
Backend API
|
v
Gemini API
|
v
AI Response
Why use a backend?
Embedding a production AI API key directly in an APK makes it possible for attackers to extract the key.
Instead:
Flutter -> FastAPI/Node/Laravel -> Gemini
The backend can implement:
- authentication
- rate limiting
- prompt templates
- logging
- usage limits
- response validation
Step 1: Create the Flutter UI
A simple chat screen can contain:
final controller = TextEditingController();
TextField(
controller: controller,
decoration: const InputDecoration(
hintText: 'Ask something...',
),
)
Send the message through a repository:
class AiRepository {
Future<String> generate(String prompt) async {
// Call your backend here.
throw UnimplementedError();
}
}
Step 2: Define a clean architecture
A scalable Flutter AI application can use:
Presentation
|
BLoC / Cubit
|
AI Repository
|
API Client
|
Backend
|
Gemini
This makes it possible to replace Gemini later without rewriting the UI.
Step 3: Backend example with FastAPI
Install dependencies:
pip install fastapi uvicorn google-genai
Example:
import os
from fastapi import FastAPI
from pydantic import BaseModel
from google import genai
app = FastAPI()
client = genai.Client(
api_key=os.environ["GEMINI_API_KEY"]
)
class ChatRequest(BaseModel):
message: str
@app.post("/chat")
async def chat(request: ChatRequest):
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=request.message,
)
return {"response": response.text}
Keep the API key in an environment variable:
export GEMINI_API_KEY="your-key"
Never commit it to Git.
Step 4: Call the backend from Flutter
Using the http package:
import 'dart:convert';
import 'package:http/http.dart' as http;
class AiApi {
final String baseUrl;
AiApi(this.baseUrl);
Future<String> chat(String message) async {
final response = await http.post(
Uri.parse('$baseUrl/chat'),
headers: {
'Content-Type': 'application/json',
},
body: jsonEncode({
'message': message,
}),
);
if (response.statusCode != 200) {
throw Exception('AI request failed');
}
final data = jsonDecode(response.body);
return data['response'] as String;
}
}
Step 5: Add loading and error states
AI requests are asynchronous, so explicitly represent:
Idle
↓
Loading
↓
Success
or
Loading
↓
Failure
With BLoC:
sealed class AiState {}
class AiInitial extends AiState {}
class AiLoading extends AiState {}
class AiSuccess extends AiState {
final String response;
AiSuccess(this.response);
}
class AiFailure extends AiState {
final String message;
AiFailure(this.message);
}
Prompt engineering
Instead of:
Explain this.
Use structured instructions:
You are an assistant for a Flutter developer.
Task:
Explain the following Dart error.
Requirements:
1. Identify the root cause.
2. Provide corrected code.
3. Keep the explanation concise.
Error:
{{error}}
Structured prompts make application behavior more predictable.
Streaming responses
For chat applications, streaming can improve perceived responsiveness:
User message
|
v
Backend
|
+---- token
+---- token
+---- token
+---- token
|
Flutter renders progressively
Consider Server-Sent Events or WebSockets depending on your backend architecture.
Security checklist
Never expose:
- Gemini API keys
- database credentials
- private backend secrets
Add:
- authentication
- request validation
- rate limiting
- logging
- abuse protection
Conclusion
Flutter is an excellent client platform for AI applications, but a maintainable architecture separates the UI from the AI provider. A backend gives you control over security, prompts, model selection, cost, and business logic.
Useful Links
SDK Flutter: https://github.com/v-modal/vmodal_sdk_flutter
SDK Android: https://github.com/v-modal/vmodal_sdk_android
Discord: https://discord.gg/K72z28KUx
Top comments (0)