· 6 min read
EmbeddingGemma 2: Google's open multimodal embedding model
EmbeddingGemma 2 embeds text, code, images, audio and video in one space and runs on-device. How it works, task prefixes, and Matryoshka sizes.

EmbeddingGemma 2 is an open multimodal embedding model from Google DeepMind, released on 6 October 2026, that turns text, code, images, audio and video into vectors in one shared space. It has 740 million parameters, runs on a phone in a few hundred megabytes of RAM, and ships under the Apache 2.0 license. If you build search or retrieval-augmented generation (RAG) and want it to work offline or on cheap hardware, this is the model to look at.
The first EmbeddingGemma was text-only. The new version keeps the small footprint and adds the other modalities, a longer context window and better code retrieval. Here is what changed, how it works, and how to use it without tripping over its sharp edges.
What is EmbeddingGemma 2?
An embedding model converts an input into a fixed-length list of numbers (a vector) so that inputs with similar meaning end up close together. You store those vectors in a database, embed the user's query the same way, and return the nearest neighbours. That is the retrieval half of most RAG systems.
EmbeddingGemma 2 is built on the Gemma 4 architecture and shares its text tokenizer and audio encoder. Google says it uses the same underlying technology as its hosted Gemini Embedding models, packaged small enough to run locally. The headline numbers from the announcement and model card:
| Property | EmbeddingGemma 2 |
|---|---|
| Parameters | 740M total |
| Modalities | Text, code, images, audio, video |
| Default output size | 768 dimensions |
| Smaller output sizes | 512, 256, 128 |
| Context | 8K tokens (4x the first version) |
| Languages | 100+ |
| License | Apache 2.0 |
On benchmarks, Google reports that its score on MTEB Code (a standard code-retrieval benchmark) rose from 68.76 to 78.68 compared with the first version, and that it leads sub-1B multimodal embedders on that benchmark and on MAEB, an audio embedding benchmark. Multilingual text quality is said to be on par with the original.
How does one model embed images, audio and text together?
The model is modular. The text core is about 270M parameters. A vision encoder (about 170M) and an audio encoder (about 300M) sit on top and can be left out if you do not need them. Whatever goes in, the output lands in the same vector space, so a text query like "dog barking at the door" can be compared directly against embeddings of audio clips or video frames.
A single input can hold a lot. Within the 8K-token window, Google lists up to about 5.5 minutes of audio, 29 images or 58 video frames, and you can interleave them with text.
The modular design matters for memory. With quantization, Google measured roughly 191MB of active RAM for the text-only weights on a Pixel 11 Pro and about 567MB for the full multimodal model. If your app only searches notes and code, you pay for the small version.
How do you use EmbeddingGemma 2 in Python?
The weights are on Hugging Face as google/embeddinggemma-2 and on Kaggle. The quickest route is sentence-transformers:
import torch
from sentence_transformers import SentenceTransformer
dtype = torch.bfloat16 if torch.cuda.is_available() and torch.cuda.is_bf16_supported() else torch.float32
model = SentenceTransformer("google/embeddinggemma-2", model_kwargs={"torch_dtype": dtype})
query = "how do I reset a forgotten password"
docs = [
"title: Account help | text: Use the 'Forgot password' link on the sign-in page.",
"title: Billing | text: Invoices are emailed on the first of each month.",
]
q = model.encode(query, prompt_name="SearchQuery")
d = model.encode(docs, prompt_name="Document")
print(model.similarity(q, d))
Two details in that snippet are easy to miss.
First, the dtype. The model card says not to run it in float16: it can return NaN values or quietly degraded embeddings without any error. Use bfloat16 where the hardware supports it, otherwise float32.
Second, the prompts. EmbeddingGemma 2 expects a short task prefix on text inputs, and the query and document sides use different ones. Leaving them off lowers quality, and nothing warns you.
Which task prefixes does it expect?
Retrieval is asymmetric: queries and documents are different kinds of text, so they get different prefixes. Classification and clustering are symmetric: every input gets the same prefix.
| Task | Prefix on text inputs |
|---|---|
| Document side | title: {title} | text: {content} (use title: none if there is no title) |
| Web or document search query | task: search result | query: {query} |
| Question answering query | task: question answering | query: {question} |
| Code search query | task: code retrieval | query: {query} |
| Classification | task: classification | query: {content} |
| Clustering | task: clustering | query: {content} |
The built-in prompt_name="Document" fills in title: none. If your documents have real titles, build the string yourself, as in the example above. Images, audio and video take no prefix.
How small can the vectors get?
The model is trained with Matryoshka Representation Learning, a technique that packs the most important information into the first dimensions of the vector, so you can cut it short and still get usable results. You can keep 512, 256 or 128 of the 768 values.
Storage drops in proportion. A float32 vector at 768 dimensions is 3,072 bytes; at 128 it is 512 bytes, which is where Google's "up to 6x" figure comes from. For a local vector store on a phone, that is the difference between fitting and not fitting.
q_small = model.encode(query, prompt_name="SearchQuery",
truncate_dim=256, normalize_embeddings=True)
The rules from the model card:
- Re-normalize after truncating. A cut-down unit vector is no longer unit length, and cosine ranking quietly suffers if you skip this.
- Use the same size for queries and documents. You cannot compare a 256-dimension query with 768-dimension documents.
- 256 is close to lossless. At 128, multimodal quality drops noticeably, so test it on your own data first.
Where can you run it?
Beyond Python, Google lists support in transformers, MLX, vLLM, SGLang, llama.cpp (GGUF files on Hugging Face), Ollama and LM Studio, plus Qdrant for storage and Unsloth for fine-tuning. For on-device apps there are LiteRT builds and a MediaPipe task, and a transformers.js demo runs it in the browser over WebGPU. Availability in Google's hosted Model Garden is listed as coming soon.
The model card is clear that this is a raw embedding model with no safety tuning or output filtering. If retrieved content reaches users, filtering is your job, and use is still subject to Gemma's prohibited-use policy.
Key takeaways
- EmbeddingGemma 2 is a 740M-parameter open model that embeds text, code, images, audio and video into one vector space.
- The text-only path needs about 191MB of RAM quantized; the full multimodal model about 567MB.
- Always use the task prefixes, and run in bfloat16 or float32, never float16.
- Matryoshka truncation to 256 dimensions saves storage with little loss; re-normalize after cutting.
FAQ
Is EmbeddingGemma 2 free for commercial use?
Yes. The weights are released under the Apache 2.0 license, which permits commercial use, alongside Gemma's prohibited-use policy.
Can I mix EmbeddingGemma 1 and 2 vectors in one index?
No. They are different models with different vector spaces. Re-embed your corpus with version 2 before switching queries over.
Do I need a GPU?
No. It is designed for phones and laptops, and runs through CPU-friendly runtimes like llama.cpp, Ollama and LiteRT. A GPU just makes bulk indexing faster.