Embeddings are just arrays of numbers
An embedding is a fixed-length list of floating-point numbers that represents the meaning of a piece of text. A typical model returns 384 to 3072 dimensions. In JSON, an embedding is simply an array:
{
"id": "chunk_3",
"text": "Refunds take 5-7 business days.",
"embedding": [0.0123, -0.3401, 0.9112, 0.0457]
}JSON is the easiest format to produce, inspect, and move around — but for embeddings it has real size and precision trade-offs worth understanding.
The size problem
A 1536-dimension embedding stored as JSON text can take several kilobytes per vector, because each float becomes a long decimal string like -0.34017293. Multiply by millions of chunks and the storage and bandwidth add up fast. Three levers reduce it:
- Round the precision. Embeddings rarely need 17 significant digits. Rounding to 6-7 decimals barely affects similarity and shrinks the payload.
- Minify. Drop whitespace — never pretty-print stored embeddings.
- Don't store embeddings in your primary JSON documents. Keep them in a vector store and reference by id.
Precision and normalization
- Most similarity search uses cosine similarity, which is unaffected by vector length, so many pipelines normalize vectors to unit length at write time.
- Storing as 32-bit floats is standard; some systems quantize to 8-bit integers to save space at a small accuracy cost.
- Keep the same model and preprocessing for both stored vectors and query vectors — mismatched embeddings produce garbage similarities.
When JSON is the wrong format
JSON is fine for transport and small sets, but for millions of vectors it is inefficient. At scale, prefer:
| Need | Better than JSON |
|---|---|
| Fast similarity search | A vector database (HNSW/IVF indexes) |
| Compact storage | Binary formats (npy, Parquet, Protobuf) |
| In-memory math | Typed arrays (Float32Array, numpy) |
A common pattern: compute and move embeddings as JSON during development, then store them in a vector DB and keep only metadata as JSON in production.
A pragmatic serialization helper
// Round to 6 decimals to shrink the JSON without hurting similarity
function packEmbedding(vec) {
return vec.map((x) => Math.round(x * 1e6) / 1e6);
}