Skip to content
Back to writing
PythonArchitectureSample

Serving Python ML models behind a Node API

May 2, 20266 min readBy Nishant Kumar

Getting a model into production

A trained model is not a product until something can call it. There are two patterns worth knowing, and the wrong one will cost you uptime.

Pattern A: a separate inference service

Keep Python and Node in separate processes. Serve the model from FastAPI and have your Node API call it over HTTP.

app.post('/api/predict', async (req, res) => {
  const response = await fetch(process.env.INFERENCE_URL + '/predict', {
    method: 'POST',
    body: JSON.stringify(req.body),
    headers: { 'Content-Type': 'application/json' },
  });
  const prediction = await response.json();
  res.status(200).json({ success: true, data: prediction });
});

This is the default choice. The two services scale independently, a model reload never restarts your API, and a Python crash does not take Node with it.

Pattern B: spawning a subprocess

app.post('/api/classify', (req, res) => { const proc = spawn('python', ['scripts/classifier.py', req.body.text]); let out = ''; proc.stdout.on('data', (d) => { out += d; }); proc.on('close', () => res.json({ success: true, classification: out })); }); ```

Only reach for this on a single box with low traffic. Every request pays full interpreter startup and reloads the model weights, which is usually far slower than the inference itself.

Which to pick

If the model is larger than a few hundred megabytes, or you expect more than a handful of requests per second, use Pattern A. We have never regretted the extra service; we have regretted the subprocess.