npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nodepyx

v1.0.1

Published

Run Python libraries from Node.js as if they were Native — embed CPython in-process with full TypeScript types, Proxy-based API, async/await support, and Next.js integration

Readme

nodepyx

Run Python libraries from Node.js as if they were native — embed CPython in-process with full TypeScript types, Proxy-based API, async/await support, and Next.js integration.

npm version License: MIT Node.js Python

Why nodepyx?

Traditional Python↔Node.js bridges spawn a separate Python process and communicate via stdin/stdout or HTTP — introducing serialization overhead, process startup latency, and complex lifecycle management.

nodepyx embeds CPython directly inside the Node.js process via a native N-API addon. Every Python call happens in-process: no IPC, no child processes, no HTTP servers.

| Feature | nodepyx | python-shell / pythonia | gRPC/HTTP | |---------|--------|------------------------|-----------| | In-process (zero IPC) | ✅ | ❌ | ❌ | | TypeScript types | ✅ Full .d.ts | Partial | Manual | | await on Python objects | ✅ Proxy thenable | ❌ | ❌ | | NumPy zero-copy | ✅ SharedArrayBuffer | ❌ | ❌ | | DataFrame native | ✅ DataFrameResult | ❌ | ❌ | | Next.js integration | ✅ withnodepyx() | ❌ | ❌ | | Auto venv/conda | ✅ | Partial | ❌ |


Quick Start

npm install nodepyx
import { init, py } from 'nodepyx';

await init({
  virtualenv: {
    path:        './.venv',
    packages:    ['pandas', 'numpy', 'scikit-learn'],
    autoInstall: true,
  },
});

// Import Python modules — works exactly like Python `import`
const pd  = await py.import('pandas');
const np  = await py.import('numpy');

// Call functions with await
const df  = await pd.read_csv('data.csv');
const arr = await np.arange(100);          // → Float64Array

// Chain attribute access
const mean = await df.describe().loc['mean'];

// Iterate Python generators
for await (const row of df.iterrows()) {
  console.log(row);
}

Installation

Prerequisites

  • Node.js ≥ 18.0.0
  • Python 3.8 – 3.12 (auto-detected; or set nodepyx_PYTHON)
  • C++ build tools (for native addon)
    • Linux: gcc, g++, make, python3
    • macOS: Xcode Command Line Tools (xcode-select --install)
    • Windows: Visual Studio Build Tools + Python
# Install from npm
npm install nodepyx

# Or with pre-built binary (skips compilation)
nodepyx_SKIP_BUILD=1 npm install nodepyx && npm run download-prebuilds

Configuration

import { init } from 'nodepyx';

await init({
  // Python executable (default: auto-detect)
  pythonExecutable: '/usr/bin/python3.11',

  // Virtualenv (recommended)
  virtualenv: {
    path:        './.venv',
    packages:    ['pandas>=2.0', 'numpy>=1.24', 'scikit-learn'],
    autoInstall: true,    // install missing packages automatically
    autoCreate:  true,    // create venv if it does not exist
  },

  // OR use Conda
  conda: {
    envName:  'my-env',
    packages: ['pytorch', 'torchvision'],
  },

  // Thread pool for GIL management
  threadPoolSize: 4,        // default: 4

  // Logging
  logLevel: 'info',         // 'debug' | 'info' | 'warn' | 'error'

  // Memory limits
  memory: {
    heapLimitMB: 2048,
    gcThresholdMB: 512,
  },
});

API Reference

Lifecycle

import { init, shutdown, isInitialized } from 'nodepyx';

await init(config?);      // Initialize Python runtime
await shutdown();         // Release all Python resources
isInitialized();          // → boolean

py — Main Proxy Object

import { py } from 'nodepyx';

// Import a module
const np = await py.import('numpy');

// Evaluate a Python expression
const result = await py.eval('1 + 2 + 3');  // → 6

// Execute statements
await py.exec(`
  import sys
  print(sys.version)
`);

// Run a .py file
await py.runFile('./my_script.py');

// Install packages at runtime
await py.installPackages(['requests', 'httpx']);

Proxy API

Every Python object returned by nodepyx is a JavaScript Proxy with full await support:

const pd = await py.import('pandas');

// Attribute access
const version = await pd.__version__;      // string

// Method calls
const df = await pd.DataFrame({ a: [1,2,3], b: [4,5,6] });
const shape = await df.shape;              // [3, 2]
const desc  = await df.describe();         // DataFrameResult

// Chained calls
const top5 = await df.sort_values('a', { ascending: false }).head(5);

// Indexing  (df['column'])
const col = await df['a'];                 // SeriesResult

NumPy Arrays

const np  = await py.import('numpy');
const arr = await np.linspace(0, 1, 100);  // NumPyArrayResult

// NumPyArrayResult interface:
arr.data     // Float64Array (or Int32Array, Uint8Array, etc.)
arr.shape    // number[]  — e.g. [100] or [3, 4]
arr.dtype    // 'float64' | 'float32' | 'int32' | ...
arr.ndim     // number
arr.size     // number — total element count

// Send TypedArrays back to Python
const NumpyBridge = new NumpyBridge();
const wire = NumpyBridge.serializeTypedArray(new Float64Array([1,2,3]), { dtype:'float64', itemsize:8 }, [3]);

Pandas DataFrames

const pd = await py.import('pandas');
const df = await pd.read_csv('data.csv');  // DataFrameResult

// DataFrameResult interface:
df.columns   // string[]
df.records   // Record<string, unknown>[]  — one object per row
df.index     // unknown[]
df.dtypes    // Record<string, string>
df.shape     // [rows, cols]

// Static helpers
import { DataFrameBridge } from 'nodepyx';
const cols = DataFrameBridge.toColumnArrays(df);  // column-keyed arrays
const filtered = DataFrameBridge.filterRows(df, row => row.score > 0.9);
const stats = DataFrameBridge.describeColumn(df, 'price');  // {count,mean,std,min,max}

Error Handling

import { PythonError, isPythonError, isPythonErrorOfType } from 'nodepyx';

try {
  await py.eval('1 / 0');
} catch (err) {
  if (isPythonError(err)) {
    console.log(err.pythonType);   // 'ZeroDivisionError'
    console.log(err.message);      // '[Python ZeroDivisionError] division by zero'
    console.log(err.traceback);    // Full Python traceback
  }
}

// Type-specific check
if (isPythonErrorOfType(err, 'ImportError')) { ... }

Environment Management

Virtualenv (recommended)

import { VenvManager } from 'nodepyx';

const mgr = new VenvManager({
  venvPath:   './.venv',
  packages:   ['pandas', 'numpy', 'scikit-learn'],
  autoCreate: true,
});

const result = await mgr.setup();
console.log('Installed:', result.installedPackages);
console.log('Venv python:', result.pythonExecutable);

Conda

import { CondaManager } from 'nodepyx';

const conda = new CondaManager({ envName: 'ml-env', packages: ['pytorch', 'pip::some-pip-package'] });
const result = await conda.setup();

PackageInstaller

import { PackageInstaller } from 'nodepyx';

const pip = new PackageInstaller({ pythonExecutable: '/usr/bin/python3' });

// Install with progress events
pip.on('progress', (ev) => console.log(ev.package, ev.status));

const result = await pip.install(['pandas>=2.0', 'numpy>=1.24']);
console.log('installed:', result.installed);
console.log('already present:', result.alreadyInstalled);

TypeScript Stubs

# Generate .d.ts stubs for Python modules
npx nodepyx-stubs pandas numpy sklearn torch

# Regenerate all cached stubs
npx nodepyx-stubs --all

# List cached stubs
npx nodepyx-stubs --list

Then in your TypeScript code:

import type { DataFrame } from 'nodepyx/pandas';   // full IDE autocomplete
import type { ndarray }   from 'nodepyx/numpy';

Next.js Integration

// next.config.js
const { withnodepyx } = require('nodepyx/next');

module.exports = withnodepyx({
  // your Next.js config
}, {
  virtualenv: { path: './.venv', packages: ['pandas'], autoInstall: true },
});
// app/api/python/route.ts  (Server Route — Node.js runtime only)
import { NextResponse } from 'next/server';
import { init, evalPython } from 'nodepyx';

let ready = false;
async function ensureReady() {
  if (!ready) { await init(); ready = true; }
}

export async function GET() {
  await ensureReady();
  const result = await evalPython('list(range(10))');
  return NextResponse.json(result);
}
// Client component
'use client';
import { usePython } from 'nodepyx/next';

export function Chart() {
  const { data, loading, run } = usePython(async (py) => {
    const np = await py.import('numpy');
    return (np as any).random.randn(100).tolist();
  });

  return <button onClick={run}>{loading ? '…' : 'Generate'}</button>;
}

Plugins

import { init } from 'nodepyx';
import type { nodepyxPlugin } from 'nodepyx';

const myPlugin: nodepyxPlugin = {
  name: 'my-plugin',
  version: '1.0.0',
  supportedModules: ['my_lib'],
  handledTypes: ['MySpecialType'],

  async onInit(ctx) {
    ctx.registerTypeHandler('MySpecialType', (raw, typeHint) => {
      // Transform raw wire dict into a JS value
      return { specialData: JSON.parse(raw.data as string) };
    });
  },
};

await init({ plugins: [myPlugin] });

Supported Python Versions

| Python | Status | |--------|--------| | 3.12 | ✅ Recommended | | 3.11 | ✅ Supported | | 3.10 | ✅ Supported | | 3.9 | ✅ Supported | | 3.8 | ✅ Supported (EOL) | | 3.7 | ❌ Not supported |


License

MIT © nodepyx contributors