Logoflutter_gemma

Models

Supported models, file formats, capabilities, ModelType reference, and download URLs.

flutter_gemma supports Gemma 4, Gemma3n, FastVLM, Qwen2-VL, SmolVLM2, LLaVA-OneVision, Gemma 3, FunctionGemma, Qwen3, Qwen 2.5, Phi-4 (incl. Phi-4 Mini Reasoning), DeepSeek R1, SmolLM, SmolLM3 and more. Desktop platforms (macOS, Windows, Linux) require the .litertlm model format.

Model file types#

Flutter Gemma supports different model file formats, grouped into two types based on how chat templates are handled.

Type 1: SDK-managed templates#

  • .task files: MediaPipe-optimized format for mobile (Android/iOS) and web.
  • .litertlm files: LiteRT-LM format for Android, iOS, Desktop, and web (early preview). Never handled by MediaPipe β€” the two formats go to different engines.

Chat templates are applied by the runtime rather than by your code β€” MediaPipe for .task, LiteRT-LM for .litertlm β€” on every platform, iOS included.

Type 2: Manual template formatting#

  • .bin files: standard binary format.
  • .tflite files: LiteRT format (formerly TensorFlow Lite).

Both formats require manual chat template formatting in your code.

Type 3: System OS models (no file)#

Gemini Nano (Android, via AICore / ML Kit GenAI), Apple Foundation Models (iOS 26+/macOS), and Gemini Nano via the Chrome Prompt API (Web β€” desktop Chrome/Edge) are built into the OS/browser β€” there is no model file to bundle or download; the platform owns the weights. Add flutter_gemma_builtin_ai, register BuiltInAiEngine(), and use ModelFileType.builtIn. Availability is device-gated β€” Gemini Nano needs Pixel 9+/Galaxy S25+, and Apple FM needs Apple Intelligence enabled on iPhone 15 Pro+/M-series. On Android the package requires minSdk 26.

πŸ‘‰ See Built-in AI for the full setup, the availability probe (BuiltInAi.availability() / BuiltInAi.ensureReady()), and fallback guidance.

`ModelFileType` is what selects the engine β€” it is **not** inferred from the file name. `installModel` defaults it to `ModelFileType.task`, so declare it explicitly: `ModelFileType.litertlm` for `.litertlm` files (omitting it routes the model to MediaPipe, which cannot read that format), `ModelFileType.task` for `.task`, `ModelFileType.binary` for `.bin` and `.tflite`, and `ModelFileType.builtIn` for OS-provided models.

Format by platform#

Format Android iOS Web Desktop Use Case
.task βœ… βœ… βœ… ❌ Older models (Gemma3n, Gemma 3, DeepSeek, Qwen 2.5, Phi-4)
.litertlm βœ… βœ… ΒΉ ⚠️ Β² βœ… Newer models (Gemma 4, Qwen3, FastVLM + desktop for all)
-web.task ❌ ❌ βœ… ❌ Web-specific builds (e.g. Gemma 4, Gemma3n)
.bin βœ… βœ… βœ… ❌ Manual chat template formatting required
.tflite βœ… βœ… βœ… βœ… Embeddings only (EmbeddingGemma, Gecko)

ΒΉ iOS .litertlm runs on the FFI engine β€” vision and audio supported on physical devices. The Simulator stays CPU-only because Metal sim has a 256 MB single-allocation cap.

Β² Web .litertlm is an early preview via @litert-lm/core β€” text plus function calling. No vision, audio, thinking or LoRA; see the feature matrix in Troubleshooting. For full multimodal on web, use a MediaPipe .task build.

Model capabilities#

Model Family Best For Function Calling Thinking Mode Vision Languages Size
Gemma 4 E2B Next-gen multimodal chat β€” text, image, audio βœ… βœ… ΒΉ βœ… Multilingual 2.4GB
Gemma 4 E4B Next-gen multimodal chat β€” text, image, audio βœ… βœ… ΒΉ βœ… Multilingual 4.3GB
Gemma3n On-device multimodal chat and image analysis βœ… ❌ βœ… Multilingual 3-6GB
FastVLM 0.5B Fast vision-language inference ❌ ❌ βœ… Multilingual 0.5GB
Qwen2-VL 2B Vision-language chat (image + text) ❌ ❌ βœ… Multilingual 1.8GB
SmolVLM2 500M Compact vision-language model ❌ ❌ βœ… Multilingual 0.36GB
LLaVA-OneVision 0.5B Compact vision-language model ❌ ❌ βœ… Multilingual 0.83GB
Phi-4 Mini Advanced reasoning and instruction following βœ… ❌ ❌ Multilingual 3.9GB
Phi-4 Mini Reasoning Step-by-step reasoning ❌ ⚠️ ‑ ❌ Multilingual 2.8GB
DeepSeek R1 High-performance reasoning and code generation βœ… βœ… ❌ Multilingual 1.7GB
Qwen3 0.6B Compact multilingual chat with function calling βœ… βœ… ❌ Multilingual 586MB
Qwen 2.5 Strong multilingual chat and instruction following βœ… ❌ ❌ Multilingual 0.5-1.6GB
Gemma 3 1B Balanced and efficient text generation βœ… ❌ ❌ Multilingual 0.5GB
Gemma 3 270M Ideal for fine-tuning (LoRA) for specific tasks ❌ ❌ ❌ Multilingual 0.3GB
FunctionGemma 270M Specialized for function calling on-device βœ… ❌ ❌ Multilingual 284MB
SmolLM 135M Ultra-compact, resource-constrained devices ❌ ❌ ❌ English 135MB
LFM2.5 230M Smallest entry; no HF token needed ❌ ❌ ❌ Multilingual 168MB
SmolLM3 3B Multilingual small LLM with reasoning mode ❌ ⚠️ ‑ ❌ Multilingual 2.0GB
TranslateGemma 4B † Single-shot 55-language translation ❌ ❌ ❌ 55 languages 2-4GB

ΒΉ Gemma 4 Thinking Mode needs the native extraContext channel: Android, iOS and Desktop only. Qwen3 and DeepSeek R1 reasoning is split out of the text by flutter_gemma itself, so it works on every platform including Web.

‑ Reasons, but emits no ThinkingResponse. These models run as ModelType.general, which has no reasoning parser β€” their thinking blocks arrive inside the answer as ordinary text and are not stripped. See Thinking Mode.

† **TranslateGemma is CPU-only for now.** Google hasn't released a mobile/desktop `.litertlm` bundle ([HF discussion #5](https://huggingface.co/google/translategemma-4b-it/discussions/5)). The community-converted bundle from [`barakplasma/translategemma-4b-it-android-task-quantized`](https://huggingface.co/barakplasma/translategemma-4b-it-android-task-quantized) runs correctly on the **CPU** and returns only padding on the **GPU**.

Measured here on an M4 Pro (macOS, Metal), both published artifacts, same prompt and the same session code, backend the only variable:

artifactPreferredBackend.cpuPreferredBackend.gpu
int4-generic (2.0 GB, INT4 blockwise)Guten Morgen997 <pad> tokens, nothing else
dynamic_int8-generic (3.9 GB, INT8 channelwise)Guten Morgen997 <pad> tokens, nothing else

Nothing fails: the Metal engine is created, activeBackend reports gpu (so it is not a silent fallback), generation runs and emits padding until it reaches the context limit. A gemma-4-E2B-it.litertlm bundle on the same machine, the same code path and the same backend answers correctly with no padding, so this is not the Metal path in general. Earlier revisions of this page said the bundle crashed the LiteRT GPU partitioner because its EMBEDDING_LOOKUP weights stay float32. Nothing in the runs above crashes, so that description does not hold; the repository has published these .litertlm artifacts since 2026-03-31, so it did not describe a later change either. Reproducing across two different quantization recipes also rules the bit width out.

Tracked at LiteRT-LM#1748. Use PreferredBackend.cpu for this model (β‰ˆ90 s prefill on a 4 B int4 bundle on M-series Macs). If you are converting it yourself, AI Edge Quantizer is the supported route today β€” the litert-lm quantization CLI announced in that thread never shipped β€” with published recipes and Model Explorer for the layer regexes (maintainer's pointers).

ModelType reference#

When installing models, specify the correct ModelType:

Model FamilyModelTypeExamples
Gemma 4ModelType.gemma4Gemma 4 E2B, Gemma 4 E4B (native function-call tokens)
Gemma 3 / Gemma3nModelType.gemmaItGemma 3 1B, Gemma 3 270M, Gemma3n E2B/E4B
DeepSeekModelType.deepSeekDeepSeek R1
Qwen 2.5ModelType.qwenQwen 2.5 1.5B, Qwen 2.5 0.5B
Qwen 3ModelType.qwen3Qwen3 0.6B
Phi-4ModelType.phiPhi-4 Mini (parses Phi's own tool-call markers)
FunctionGemmaModelType.functionGemmaFunctionGemma 270M IT
GeneralModelType.generalFastVLM 0.5B, SmolLM 135M, LFM2.5 230M, SmolLM3 3B, Phi-4 Mini Reasoning, Qwen2-VL 2B, SmolVLM2 500M, LLaVA-OneVision 0.5B
Gemma 4 uses `ModelType.gemma4` so its native tool-call tokens are routed through the LiteRT-LM SDK's chat-template path. For Gemma 3 and earlier, keep `ModelType.gemmaIt`.

Usage example:

// Gemma models
await FlutterGemma.installModel(modelType: ModelType.gemmaIt)
  .fromNetwork(url).install();

// DeepSeek models
await FlutterGemma.installModel(modelType: ModelType.deepSeek)
  .fromNetwork(url).install();

// Phi-4 (its own type β€” parses Phi's tool-call markers)
await FlutterGemma.installModel(modelType: ModelType.phi)
  .fromNetwork(url).install();

Supported models & platforms#

ModelSizeDesktopMobileWeb
Gemma 4 E2B2.4GBβœ…βœ…βœ…
Gemma 4 E4B4.3GBβœ…βœ…βœ…
Gemma3n E2B3.1GBβœ…βœ…βœ…
Gemma3n E4B6.5GBβœ…βœ…βœ…
FastVLM 0.5B0.5GBβœ…βŒβŒ
Qwen2-VL 2B1.8GBβœ…βœ…βŒ
SmolVLM2 500M0.36GBβœ…βœ…βŒ
LLaVA-OneVision 0.5B0.83GBβœ…βœ…βŒ
Gemma-3 1B0.5GBβœ…βœ…βœ…
Gemma 3 270M0.3GBβœ…βœ…βœ…
FunctionGemma 270M284MBβœ…βœ…βœ…
Qwen3 0.6B586MBβœ…βœ…βœ…
Qwen 2.5 1.5B1.6GBβœ…βœ…βŒ
Qwen 2.5 0.5B0.5GBβŒβœ…βŒ
SmolLM 135M135MBβŒβœ…βŒ
LFM2.5 230M168MBβœ…βœ…βŒ
SmolLM3 3B2.0GBβœ…βœ…βŒ
Phi-4 Mini3.9GBβœ…βœ…βœ…
Phi-4 Mini Reasoning2.8GBβœ…βœ…βŒ
DeepSeek R11.7GBβŒβœ…βŒ

Installation sources#

// Network β€” .litertlm is the cross-platform default (Android/iOS/Desktop).
// For mobile-only or web-only apps you can substitute a .task URL β€” and drop
// the fileType, which defaults to ModelFileType.task.
await FlutterGemma.installModel(
  modelType: ModelType.gemmaIt,
  fileType: ModelFileType.litertlm,
)
  .fromNetwork('https://example.com/model.litertlm', token: 'optional')
  .install();

// Flutter assets
await FlutterGemma.installModel(
  modelType: ModelType.gemmaIt,
  fileType: ModelFileType.litertlm,
)
  .fromAsset('assets/models/model.litertlm')
  .install();

// Native bundle
await FlutterGemma.installModel(
  modelType: ModelType.gemmaIt,
  fileType: ModelFileType.litertlm,
)
  .fromBundled('model.litertlm')
  .install();

// External file (native only)
await FlutterGemma.installModel(
  modelType: ModelType.gemmaIt,
  fileType: ModelFileType.litertlm,
)
  .fromFile('/path/to/model.litertlm')
  .install();

Hugging Face#

Install a model straight from a Hugging Face repo. The resolver that reads a repo's deployment manifest ships with the engine, so registering the engine is enough β€” there is no separate resolver list to maintain.

One call (manifest-driven) β€” omit file, and fromHuggingFace(repo) resolves the repo's manifest (e.g. litertlm_manifest.json) at install time, installs the right revision-pinned variant for the device, and returns the manifest's overridable runtime defaults on the result:

// The engine carries its resolver β€” nothing else to register.
await FlutterGemma.initialize(inferenceEngines: [LiteRtLmEngine()]);

final install = await FlutterGemma.installModel(
  modelType: ModelType.general,     // fallback β€” the manifest overrides it
  fileType: ModelFileType.litertlm, // selects the litertlm resolver
)
  .fromHuggingFace('litert-community/Qwen3-4B-Thinking-2507')
  .install();

final model = await FlutterGemma.getActiveModel(defaults: install.runtime);
// `minOutputTokens` is a FLOOR, not a cap β€” leave `maxOutputTokens` unset (or
// keep it >= `install.runtime?.minOutputTokens`). Passing the floor as the cap
// would truncate a reasoning model mid-thought.
final session = await model.createSession(
  enableThinking: install.runtime?.isThinking ?? false,
);

.onnx repos install the whole ORT-GenAI directory β€” the ONNX resolver (carried by OnnxEngine) lists the repo, picks a CPU execution-provider folder (the bundled runtime is CPU-only; pin one with OnnxHuggingFaceResolver(variant: …)) and downloads every file in it; see ONNX. .builtIn repos surface that OS models have no Hugging Face file.

Explicit file β€” pass file, and fromHuggingFace(repo, file:) resolves …/resolve/<revision>/<file> and installs it directly, for any fileType (no manifest needed; the HF token is applied to huggingface.co automatically):

await FlutterGemma.installModel(
  modelType: ModelType.gemmaIt,
  fileType: ModelFileType.litertlm,
)
  .fromHuggingFace('litert-community/Gemma3-1B-IT', file: 'model.litertlm', token: 'optional')
  .install();

Inspect first β€” resolveHuggingFace(repo, fileType:) returns the resolved identity plus overridable runtime defaults WITHOUT installing, so you can inspect the variant, its notes, and defaults before committing:

final r = await FlutterGemma.resolveHuggingFace(
  'litert-community/Qwen3-4B-Thinking-2507',
  fileType: ModelFileType.litertlm,
);
// … inspect r.file / r.notes / r.runtime …
await FlutterGemma.installModel(
  modelType: r.modelType ?? ModelType.general,
  fileType: r.fileType,
)
  .fromNetwork(r.url) // r.url pins the resolver's revision
  .install();

The resolver lives in the engine package β€” LitertlmManifestResolver in flutter_gemma_litertlm reads litertlm_manifest.json β€” and rides on the engine via HuggingFaceResolverSource, so initialize(inferenceEngines: […]) auto-registers it. Pass initialize(huggingFaceResolvers: [...]) only to override an engine's default (e.g. LitertlmManifestResolver(revision: 'abc123') to pin a commit).

Source capabilities#

Source TypePlatformProgressResumeAuthenticationUse Case
NetworkSourceAllβœ… Detailed⚠️ Server-dependentβœ… SupportedHuggingFace, CDNs, private servers
AssetSourceAll⚠️ End only❌ No❌ N/AModels bundled in app assets
BundledSourceAll⚠️ End only❌ No❌ N/ANative platform resources
FileSourceNative (no Web)⚠️ End only❌ No❌ N/AUser-selected files (file picker)
Resume after interruption is server-dependent and **not supported by the HuggingFace CDN** β€” flutter_gemma uses smart retry logic with exponential backoff and automatic restart instead. See [Troubleshooting](/docs/troubleshooting).

Android foreground service (large downloads)#

Android has a 9-minute background execution limit. A foreground service shows a notification and exempts the download from battery-optimization kills, and you have to ask for it β€” the default configures no notification, and the platform will not start the service without one, so file size alone changes nothing:

// DEFAULT β€” no foreground service; pass foreground: true to get one
await FlutterGemma.installModel(modelType: ModelType.gemmaIt)
  .fromNetwork(url)  // foreground: null
  .install();

// Force foreground mode
await FlutterGemma.installModel(modelType: ModelType.gemmaIt)
  .fromNetwork(url, foreground: true)
  .install();

iOS uses native URLSession which handles long downloads automatically β€” no foreground service needed.

Cancelling downloads#

import 'package:flutter_gemma/core/model_management/cancel_token.dart';

final cancelToken = CancelToken();

final future = FlutterGemma.installModel(modelType: ModelType.gemmaIt)
  .fromNetwork(url)
  .withCancelToken(cancelToken)
  .withProgress((progress) => print('Progress: $progress%'))
  .install();

// Cancel from elsewhere (e.g. user pressed a cancel button)
cancelToken.cancel('User cancelled download');

try {
  await future;
} catch (e) {
  if (CancelToken.isCancel(e)) {
    print('Download was cancelled by user');
  }
}

CancelToken cancels all files in multi-file downloads (e.g. embedding model + tokenizer), works on mobile + web, and throws DownloadCancelledException.

Speech models#

On-device speech via the opt-in flutter_gemma_speech package β€” selectable, profile-driven pipelines (you pick the model with SttModelType / TtsModelType). moonshine-tiny, Whisper, and Parakeet (STT) and Matcha, Qwen3-TTS (multilingual), and Inflect-Nano-v2 (fast) TTS work end-to-end today; kokoro / supertonic TTS voices are follow-ons. Native only (no Web). See Speech for usage. A VoiceSession also chains STT β†’ LLM β†’ TTS into a push-to-talk voice loop β€” see Speech.

Speech-to-text

ModelInputSizeStatusAuth
moonshine-tinyraw 16 kHz PCM~104 MBβœ… end-to-end❌
Whisper (tiny / base)log-melβ€”βœ… end-to-end❌
Parakeet (CTC 0.6B)log-melβ€”βœ… end-to-end❌

Whisper is multilingual β€” the shipped checkpoints are the multilingual ones (no .en suffix), so all 99 of Whisper's languages are available. Set a default for the recognizer, override it per transcription, or both:

// Default for every transcription on this recognizer.
final stt = await FlutterGemma.getActiveStt(language: 'de');
final german = await stt.transcribe(germanPcm);

// One call in another language β€” same recognizer, nothing reloaded.
final french = await stt.transcribe(frenchPcm, language: 'fr');

Both are free: the language is one token in the decoder's seed prompt, and that prompt is rebuilt on every transcription. Switching languages never reloads the model or invalidates the recognizer you are holding.

The value is Whisper's own language code without the delimiters, and it defaults to 'en'. It decides the OUTPUT language only β€” the weights understand the audio either way, so asking for 'en' on German speech returns an English translation rather than an error.

Moonshine and Parakeet have no language token in their decoder prompt and reject the parameter with an ArgumentError rather than ignoring it; both are English-only.

Text-to-speech

ModelOutputSizeStatusAuth
Matcha16-bit PCM @ 22050 Hz~90 MBβœ… end-to-end❌
Qwen3-TTS (10 langs + auto)16-bit PCM~1.9 GBβœ… end-to-end❌
Inflect-Nano-v2 (fast)16-bit PCM @ 24 kHz~8 MBβœ… end-to-end❌

Text embedding models#

The LiteRT embedding models below generate 768-dimensional vectors. The numbers in names (64/256/512/1024/2048) indicate maximum input sequence length in tokens, not embedding dimension. (With the ONNX backend the dimension is model-dependent β€” e.g. all-MiniLM-L6-v2 is 384-dim.) See Embeddings & RAG for usage.

ModelParametersDimensionsMax Seq LengthSizeAuth Required
Gecko 64110M768D64 tokens110MB❌
Gecko 256110M768D256 tokens114MB❌
Gecko 512110M768D512 tokens116MB❌
EmbeddingGemma 256300M768D256 tokens179MBβœ…
EmbeddingGemma 512300M768D512 tokens179MBβœ…
EmbeddingGemma 1024300M768D1024 tokens183MBβœ…
EmbeddingGemma 2048300M768D2048 tokens196MBβœ…

Performance (Android Pixel 8):

  • Gecko 64: ~109 ms/doc embedding, 130 ms search (fastest β€” 2.6Γ— faster than EmbeddingGemma).
  • EmbeddingGemma 256: ~286 ms/doc embedding, 342 ms search (more accurate β€” 300M vs 110M params).

SigLIP 2 text tower (ONNX, manual wiring)#

flutter_gemma_embeddings ships a SigLIP 2 text profile, for putting text into the same space as SigLIP's vision tower β€” image↔text retrieval rather than document RAG. It is the only embedding profile here that is not installed through installEmbedder().

Text in, vectors out β€” the plugin does not run the vision tower. You embed the image side elsewhere (or offline) and query it with vectors this profile produces.

Its convention differs from every model above: no leading BOS, a single trailing <eos>, lowercased text, and a fixed 64-token width that lives in the token ids because the int8 export carries no attention_mask. It also ignores the TaskType prefix β€” the vision tower encodes an image with no prefix, so adding one moves the text vector off the space the two towers share.

SigLIP 2 reuses the Gemma BPE vocabulary, so a tokenizer.json cannot be told apart by its vocabulary alone, and the ONNX tokenizer loader refuses such a file rather than reading it with Gemma's convention and returning a plausible but wrong vector.

To tell whether an export is the one this profile expects, look at two blocks of its tokenizer.json β€” the same two the refusal keys on:

  • "padding" declares a fixed width β€” "strategy": {"Fixed": …}, not "BatchLongest"
  • "post_processor" appends <eos> and prepends no <bos>

The refusal needs both, so there are three outcomes rather than two. A file matching both is SigLIP 2's convention. One that prepends <bos> is an EmbeddingGemma-family file and belongs on the profiles above. A file failing either check β€” no padding block, "BatchLongest", or a post_processor that is missing, empty, or does not end in a special token β€” is not classified at all: it is read with Gemma's convention and nothing is raised.

So do not read the absence of an error as approval. A SigLIP 2 export that declares both blocks is caught, but one that dropped either β€” a re-export, or a tool that strips them β€” reaches the Gemma path and produces exactly the silently wrong vector this section warns about.

Wire it yourself:

import 'package:flutter_gemma_embeddings/embedding_tokenizer.dart'
    show loadSiglipSentencePieceEmbeddingTokenizer;

and pass that as the tokenizer factory of the ForwardPassDescriptor you give to CommonEmbeddingModel.create. That library is native-only. See the flutter_gemma_embeddings README for the full profile, and ONNX Runtime for why the factory declines to guess.