I have an Express Node.js application, but I also have a machine learning algorithm to use in Python. Is there a way I can call Python functions from my Node.js application to make use of the power of machine learning libraries?
-
4[node-python](https://www.npmjs.org/package/node-python). Never used it myself, though. – univerio May 03 '14 at 22:36
-
41Two years later, ```node-python``` seems to be an abandoned project. – imrek May 03 '16 at 18:26
-
8https://github.com/extrabacon/python-shell – Ulad Kasach Sep 18 '17 at 14:32
-
See also https://github.com/QQuick/Transcrypt for compiling python into javascript and then invoking it – Jonathan May 06 '19 at 22:38
-
Checkout https://github.com/extremeheat/JSPyBridge/ – Extreme Jul 18 '21 at 08:56
12 Answers
Easiest way I know of is to use "child_process" package which comes packaged with node.
Then you can do something like:
const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["path/to/script.py", arg1, arg2, ...]);
Then all you have to do is make sure that you import sys
in your python script, and then you can access arg1
using sys.argv[1]
, arg2
using sys.argv[2]
, and so on.
To send data back to node just do the following in the python script:
print(dataToSendBack)
sys.stdout.flush()
And then node can listen for data using:
pythonProcess.stdout.on('data', (data) => {
// Do something with the data returned from python script
});
Since this allows multiple arguments to be passed to a script using spawn, you can restructure a python script so that one of the arguments decides which function to call, and the other argument gets passed to that function, etc.
Hope this was clear. Let me know if something needs clarification.

- 13,341
- 16
- 97
- 165

- 4,035
- 1
- 17
- 26
-
1I tried to run a small Python script from within my node server and the solution that worked for me was to use exec = require('child_process').exec (reference: https://nodejs.org/docs/v0.2.4/api.html). – Paulo S. Abreu Sep 12 '15 at 00:25
-
25@PauloS.Abreu: The problem I have with `exec` is that it returns a buffer instead of a stream, and if your data exceeds the `maxBuffer` setting, which defaults to 200kB, you get a buffer exceeded exception and your process is killed. Since `spawn` uses streams, it is more flexible than `exec`. – theJoestJoeToEverJoe Jan 13 '16 at 21:36
-
@jYeager can path to python here refer to a url for AWS ec2 instance? My Node.js will be on Heroku's server whereas the python script I want to run is sitting on this AWS ec2 instance. – claude computing Sep 17 '16 at 18:58
-
1@jYeager yes it ended up not working, probably because of Heroku's restrictions on http requests. So I migrated the Node.js app to AWS, and it worked. It was all about chmod-ing. – claude computing Sep 20 '16 at 08:29
-
3Just a small note, if you use node you should probably not use the process keyword – alexvicegrab Jul 28 '17 at 16:49
-
4How should I install external pip dependencies? I need numpy for a project and cannot make it run because it doesn't have it installed. – javiergarval Jan 02 '19 at 11:43
-
3@javiergarval That would be better suited as a new question instead of a comment. – theJoestJoeToEverJoe Jan 02 '19 at 17:31
-
-
6is there any other way to return data from python other than by printing? My python script outputs a lot of log data and apparently it has trouble flushing all that data – lxknvlk Jun 10 '19 at 13:36
-
@lxknvlk Did you find any solution? Because my python script also outputs a lot of data and it does not send complete data back due to flushing limit. – Muhammad Amir Jun 08 '20 at 04:20
-
@MuhammadAmir if you need an arbitrary one-way data stream from one process to another I would recommend using a named pipe. Named pipes present themselves in the file system as a file to which you can read and write data. The data is not actually written to the file, it is instead queued until another process reads it. – Jrs.b Feb 19 '21 at 01:12
-
-
in 2022 if you use `python3` use 'python3' instead of `python` and when do you do something `console.log(data)` try `console.log(data.toString())` if you start seeing `Buffer .....` in the console – petrosmm Dec 09 '22 at 03:08
-
This doesn't really answer the question. They asked how to call a python function, but you answered how to call a python script. – philthathril Aug 18 '23 at 16:44
Example for people who are from Python background and want to integrate their machine learning model in the Node.js application:
It uses the child_process
core module:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
const { spawn } = require('child_process');
const pyProg = spawn('python', ['./../pypy.py']);
pyProg.stdout.on('data', function(data) {
console.log(data.toString());
res.write(data);
res.end('end');
});
})
app.listen(4000, () => console.log('Application listening on port 4000!'))
It doesn't require sys
module in your Python script.
Below is a more modular way of performing the task using Promise
:
const express = require('express')
const app = express()
let runPy = new Promise(function(success, nosuccess) {
const { spawn } = require('child_process');
const pyprog = spawn('python', ['./../pypy.py']);
pyprog.stdout.on('data', function(data) {
success(data);
});
pyprog.stderr.on('data', (data) => {
nosuccess(data);
});
});
app.get('/', (req, res) => {
res.write('welcome\n');
runPy.then(function(fromRunpy) {
console.log(fromRunpy.toString());
res.end(fromRunpy);
});
})
app.listen(4000, () => console.log('Application listening on port 4000!'))

- 30,738
- 21
- 105
- 131

- 7,179
- 4
- 43
- 57
-
19I'm surprised this hasn't gotten more up votes. While @NeverForgetY2K's answer is fine, this answer contains a more detailed example including the port listening, and nicely uses the more modern JS conventions like const & promises. – Mike Williamson Apr 26 '18 at 23:18
-
2Great example. Promise one was good to detect some errors i had on the python script. – htafoya Jun 14 '18 at 00:11
-
1This was super simple for me to plug and play, and easy to debug as @htafoya mentioned. Thank you! – Alex L Sep 27 '20 at 17:07
The python-shell
module by extrabacon
is a simple way to run Python scripts from Node.js with basic, but efficient inter-process communication and better error handling.
Installation:
With npm:
npm install python-shell
.
Or with yarn:
yarn add python-shell
Running a simple Python script:
const PythonShell = require('python-shell').PythonShell;
PythonShell.run('my_script.py', null, function (err) {
if (err) throw err;
console.log('finished');
});
Running a Python script with arguments and options:
const PythonShell = require('python-shell').PythonShell;
var options = {
mode: 'text',
pythonPath: 'path/to/python',
pythonOptions: ['-u'],
scriptPath: 'path/to/my/scripts',
args: ['value1', 'value2', 'value3']
};
PythonShell.run('my_script.py', options, function (err, results) {
if (err)
throw err;
// Results is an array consisting of messages collected during execution
console.log('results: %j', results);
});
For the full documentation and source code, check out https://github.com/extrabacon/python-shell

- 2,570
- 2
- 22
- 32

- 859
- 9
- 22
-
3This issue is stopping me from using it - https://github.com/extrabacon/python-shell/issues/179 – mhlavacka Feb 20 '19 at 23:56
-
5If you're getting this error - TypeError: PythonShell.run is not a function Then make sure you import it like this var {PythonShell} = require( 'python-shell'); – Mohammed Dec 21 '19 at 14:42
You can now use RPC libraries that support Python and Javascript such as zerorpc
From their front page:
Node.js Client
var zerorpc = require("zerorpc");
var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
client.invoke("hello", "RPC", function(error, res, more) {
console.log(res);
});
Python Server
import zerorpc
class HelloRPC(object):
def hello(self, name):
return "Hello, %s" % name
s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()

- 1,920
- 2
- 24
- 34
-
3You can also use https://socket.io/ on both Node and Python side. – Bruno Gabuzomeu Feb 28 '20 at 14:21
Many of the examples are years out of date and involve complex setup. You can give JSPyBridge/pythonia a try (full disclosure: I'm the author). It's vanilla JS that lets you operate on foreign Python objects as if they existed in JS. In fact, it does interoperability so Python code can in return call JS through callbacks and passed functions.
numpy + matplotlib example, with the ES6 import system:
import { py, python } from 'pythonia'
const np = await python('numpy')
const plot = await python('matplotlib.pyplot')
// Fixing random state for reproducibility
await np.random.seed(19680801)
const [mu, sigma] = [100, 15]
// Inline expression evaluation for operator overloading
const x = await py`${mu} + ${sigma} * ${np.random.randn(10000)}`
// the histogram of the data
const [n, bins, patches] = await plot.hist$(x, 50, { density: true, facecolor: 'g', alpha: 0.75 })
console.log('Distribution', await n) // Always await for all Python access
await plot.show()
python.exit()
Through CommonJS (without top level await):
const { py, python } = require('pythonia')
async function main() {
const np = await python('numpy')
const plot = await python('matplotlib.pyplot')
...
// the rest of the code
}
main().then(() => python.exit()) // If you don't call this, the process won't quit by itself.

- 315
- 4
- 7
-
How can I invoke a function from an existing Python script (with and without a class) from JavaScript? – sken130 Aug 29 '23 at 03:32
Most of previous answers call the success of the promise in the on("data"), it is not the proper way to do it because if you receive a lot of data you will only get the first part. Instead you have to do it on the end event.
const { spawn } = require('child_process');
const pythonDir = (__dirname + "/../pythonCode/"); // Path of python script folder
const python = pythonDir + "pythonEnv/bin/python"; // Path of the Python interpreter
/** remove warning that you don't care about */
function cleanWarning(error) {
return error.replace(/Detector is not able to detect the language reliably.\n/g,"");
}
function callPython(scriptName, args) {
return new Promise(function(success, reject) {
const script = pythonDir + scriptName;
const pyArgs = [script, JSON.stringify(args) ]
const pyprog = spawn(python, pyArgs );
let result = "";
let resultError = "";
pyprog.stdout.on('data', function(data) {
result += data.toString();
});
pyprog.stderr.on('data', (data) => {
resultError += cleanWarning(data.toString());
});
pyprog.stdout.on("end", function(){
if(resultError == "") {
success(JSON.parse(result));
}else{
console.error(`Python error, you can reproduce the error with: \n${python} ${script} ${pyArgs.join(" ")}`);
const error = new Error(resultError);
console.error(error);
reject(resultError);
}
})
});
}
module.exports.callPython = callPython;
Call:
const pythonCaller = require("../core/pythonCaller");
const result = await pythonCaller.callPython("preprocessorSentiment.py", {"thekeyYouwant": value});
python:
try:
argu = json.loads(sys.argv[1])
except:
raise Exception("error while loading argument")

- 1,309
- 12
- 16
I'm on node 10 and child process 1.0.2
. The data from python is a byte array and has to be converted. Just another quick example of making a http request in python.
node
const process = spawn("python", ["services/request.py", "https://www.google.com"])
return new Promise((resolve, reject) =>{
process.stdout.on("data", data =>{
resolve(data.toString()); // <------------ by default converts to utf-8
})
process.stderr.on("data", reject)
})
request.py
import urllib.request
import sys
def karl_morrison_is_a_pedant():
response = urllib.request.urlopen(sys.argv[1])
html = response.read()
print(html)
sys.stdout.flush()
karl_morrison_is_a_pedant()
p.s. not a contrived example since node's http module doesn't load a few requests I need to make

- 2,946
- 3
- 27
- 36
-
I have a server backend build on nodejs and i have few machine learning related python scripts which I spawn using child process spawn through nodejs whenever I recieve the request on my nodejs server. As suggested in this thread. My question is, is this the right way of doing it or I can have my python script run like a flask service binded to a port using zmq and run a promise from nodejs to this service. By right what I mean is, which way is the memory saving and the speed saving method? – Aswin Aug 10 '18 at 12:28
-
2You probably want the python stuff running independently. You don't want hard codes dependencies, especially for something more complicated as an ml service. What if you wanted to add another piece to this architecture? Like a caching layer in front of the ml, or a way to add extra parameters to the ml model? It's memory to run a python server as well, but you'll probably need the flexibility. Later on you can separate the two pieces to two servers – 1mike12 Aug 10 '18 at 18:02
-
He asked if he could call a *function*, this does not answer the question. – basickarl Sep 27 '18 at 13:20
-
2
The Boa is good for your needs, see the example which extends Python tensorflow keras.Sequential
class in JavaScript.
const fs = require('fs');
const boa = require('@pipcook/boa');
const { tuple, enumerate } = boa.builtins();
const tf = boa.import('tensorflow');
const tfds = boa.import('tensorflow_datasets');
const { keras } = tf;
const { layers } = keras;
const [
[ train_data, test_data ],
info
] = tfds.load('imdb_reviews/subwords8k', boa.kwargs({
split: tuple([ tfds.Split.TRAIN, tfds.Split.TEST ]),
with_info: true,
as_supervised: true
}));
const encoder = info.features['text'].encoder;
const padded_shapes = tuple([
[ null ], tuple([])
]);
const train_batches = train_data.shuffle(1000)
.padded_batch(10, boa.kwargs({ padded_shapes }));
const test_batches = test_data.shuffle(1000)
.padded_batch(10, boa.kwargs({ padded_shapes }));
const embedding_dim = 16;
const model = keras.Sequential([
layers.Embedding(encoder.vocab_size, embedding_dim),
layers.GlobalAveragePooling1D(),
layers.Dense(16, boa.kwargs({ activation: 'relu' })),
layers.Dense(1, boa.kwargs({ activation: 'sigmoid' }))
]);
model.summary();
model.compile(boa.kwargs({
optimizer: 'adam',
loss: 'binary_crossentropy',
metrics: [ 'accuracy' ]
}));
The complete example is at: https://github.com/alibaba/pipcook/blob/master/example/boa/tf2/word-embedding.js
I used Boa in another project Pipcook, which is to address the machine learning problems for JavaScript developers, we implemented ML/DL models upon the Python ecosystem(tensorflow,keras,pytorch) by the boa library.

- 59
- 2
/*eslint-env es6*/
/*global require*/
/*global console*/
var express = require('express');
var app = express();
// Creates a server which runs on port 3000 and
// can be accessed through localhost:3000
app.listen(3000, function() {
console.log('server running on port 3000');
} )
app.get('/name', function(req, res) {
console.log('Running');
// Use child_process.spawn method from
// child_process module and assign it
// to variable spawn
var spawn = require("child_process").spawn;
// Parameters passed in spawn -
// 1. type_of_script
// 2. list containing Path of the script
// and arguments for the script
// E.g : http://localhost:3000/name?firstname=Levente
var process = spawn('python',['apiTest.py',
req.query.firstname]);
// Takes stdout data from script which executed
// with arguments and send this data to res object
var output = '';
process.stdout.on('data', function(data) {
console.log("Sending Info")
res.end(data.toString('utf8'));
});
console.log(output);
});
This worked for me. Your python.exe must be added to you path variables for this code snippet. Also, make sure your python script is in your project folder.

- 21
- 1
const util = require('util');
const exec = util.promisify(require('child_process').exec);
function runPythonFile() {
const { stdout, stderr } = await exec('py ./path_to_python_file -s asdf -d pqrs');
if (stdout) { // do something }
if (stderr) { // do something }
}
For more information visit official Nodejs child process page: https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback

- 369
- 3
- 6
you can check out my package on npm https://www.npmjs.com/package/@guydev/native-python
it provides a very simple and powerful way to run python functions from node
import { runFunction } from '@guydev/native-python'
const example = async () => {
const input = [1,[1,2,3],{'foo':'bar'}]
const { error, data } = await runFunction('/path/to/file.py','hello_world', '/path/to/python', input)
// error will be null if no error occured.
if (error) {
console.log('Error: ', error)
}
else {
console.log('Success: ', data)
// prints data or null if function has no return value
}
}
python module
# module: file.py
def hello_world(a,b,c):
print( type(a), a)
# <class 'int'>, 1
print(type(b),b)
# <class 'list'>, [1,2,3]
print(type(c),c)
# <class 'dict'>, {'foo':'bar'}

- 21
- 4
-
It looks like you are promoting your own work. [Please see the instructions on self-promotion](https://stackoverflow.com/help/promotion): "_you **must** disclose your affiliation in your post._" – starball Dec 11 '22 at 20:52