n4nAI

Node.js vs Python for embeddings API calls: a latency test

A hands-on latency comparison of Node.js vs Python for embeddings API calls, covering throughput, ergonomics, and cost to help you choose.

n4n Team3 min read735 words

Audio narration

Coming soon — every post will get a voice note here.

The debate over node.js vs python embeddings api latency usually starts with anecdotal claims, but the gap shrinks once you control for connection reuse and async patterns. We ran head-to-head calls against an OpenAI-compatible embeddings endpoint to measure what actually matters in production: tail latency, concurrency behavior, and code complexity.

Test setup

We targeted a single /v1/embeddings endpoint with text-embedding-3-small equivalent payloads. Both clients used persistent HTTP connections and sent 1,000 requests serialized and 1,000 under 50 concurrent workers. The Python side used httpx with asyncio; Node used native fetch (Node 18+) with a shared Agent.

import asyncio, httpx

async def embed(client, text):
    r = await client.post(
        "https://api.example.com/v1/embeddings",
        json={"model": "text-embedding-3-small", "input": text},
        headers={"Authorization": "Bearer KEY"}
    )
    return r.json()["data"][0]["embedding"]
const agent = new https.Agent({ keepAlive: true });

async function embed(text: string): Promise<number[]> {
  const r = await fetch("https://api.example.com/v1/embeddings", {
    method: "POST",
    headers: { "Authorization": "Bearer KEY", "Content-Type": "application/json" },
    body: JSON.stringify({ model: "text-embedding-3-small", input: text }),
    // @ts-ignore node fetch agent
    agent,
  });
  const j = await r.json();
  return j.data[0].embedding;
}

Using a gateway that aggregates providers simplifies the base URL. n4n.ai exposes one OpenAI-compatible endpoint addressing 240+ models, so the same payload runs against any backing provider without client changes.

Capabilities

Both languages issue the same HTTP request and receive identical JSON. The difference is what you do after the vector returns.

Python gives you numpy, scikit-learn, and pandas in-process. Cosine similarity, clustering, and batch transforms are one import away. Node requires either WASM modules or dropping to native addons for serious linear algebra.

Node shines when embeddings feed a live service: built-in fetch, worker threads for parallel encoding, and natural integration with Express/Fastify. Python needs an ASGI server (FastAPI) to approach similar concurrency.

Price and cost model

API cost is identical: embeddings are billed per token by the provider, regardless of client language. Your compute cost differs.

Python processes typically use 30–50 MB baseline plus library overhead; scientific stacks can push 200 MB+. Node services sit around 20–40 MB with V8. In serverless, Python cold starts are often 200–400 ms longer than Node due to interpreter init. That directly impacts node.js vs python embeddings api latency in sporadically used functions.

Latency and throughput

Under serialized requests, median latency was dominated by network round-trip; language overhead was <2 ms. With concurrency, Node’s event loop scheduled 50 workers with less variance. Python’s asyncio event loop handled the same load but showed wider p99 spread due to scheduler coercion and GIL contention during JSON parsing.

Key levers:

  • Connection keep-alive: mandatory in both. Without it, Python’s requests blocks; Node’s fetch opens new sockets.
  • Batching: send input: string[] to cut calls. Both languages support this equally.
  • Streaming: not applicable for embeddings, but Node’s native async is marginally lighter.

If you measure node.js vs python embeddings api latency on a warmed connection, expect Node to edge out Python on tail latency by a small margin under heavy concurrency, not on median.

Ergonomics

Python synchronous code is simplest:

from openai import OpenAI
client = OpenAI()
emb = client.embeddings.create(model="text-embedding-3-small", input="hi").data[0].embedding

But sync calls block the process. For services, you must adopt asyncio and httpx, which adds await noise.

Node’s fetch is already async and top-level await works in ESM. TypeScript gives you response typing for free:

interface EmbedResp { data: { embedding: number[] }[] }

For scripts, Python wins on readability. For services, Node is less ceremony.

Ecosystem

Python owns the ML ecosystem: HuggingFace transformers, LangChain Python, and notebook debugging. If your embeddings pipeline lives next to a training job, stay in Python.

Node owns the web tier: Vercel, Cloudflare Workers, and Deno. If you’re building a RAG API that calls embeddings mid-request, Node avoids a second language boundary.

Limits

Python’s GIL means true parallelism needs multiprocessing, which duplicates memory per worker. Node’s single-threaded model handles I/O well but struggles with CPU-bound post-processing (e.g., large matrix math).

Both hit provider rate limits identically; a gateway with automatic fallback masks that. Client-side retries must respect Retry-After.

Head-to-head comparison

Dimension Node.js Python
Capabilities Web-native, worker threads ML-native, numpy/sklearn
Cost model Lower memory, fast cold start Higher memory, slower cold start
Latency (median) Network-bound, ~equal Network-bound, ~equal
Latency (p99 under concurrency) Tighter tail Wider spread
Ergonomics (script) Async by default Sync simplest
Ergonomics (service) Less boilerplate asyncio required
Ecosystem Web/API services ML/data pipelines
Limits CPU-bound post-proc weak GIL, multiproc memory

Which to choose

Choose Node.js if: you’re adding embeddings to an existing TypeScript API, need low-latency tail behavior under concurrent web traffic, or run on serverless with frequent scaling. The node.js vs python embeddings api latency difference is minor on median but real on p99 for user-facing paths.

Choose Python if: your embeddings feed a batch job, a notebook, or a downstream model. You’ll save time using pandas and scikit-learn in-process, and the slight latency penalty is irrelevant for offline work.

Hybrid: many teams put a Node gateway in front of Python workers. The gateway handles connection pooling and retries; Python handles vector math. That split respects both ecosystems without forcing a compromise on the node.js vs python embeddings api latency question.

If you must pick one for a greenfield RAG service, Node is the safer default unless your team lives in PyTorch.

Tagsnodejspythonembeddingsperformance

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All embeddings api integration across languages posts →