Title: Using WordPress Playground in Node.js
Published: July 15, 2026
Last modified: July 16, 2026

---

# Using WordPress Playground in Node.js

## In this article

 * [WebAssembly PHP for Node.js](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#webassembly-php-for-node-js)
    - [Basic usage](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#basic-usage)
    - [Loading PHP extensions](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#loading-php-extensions)
 * [Use cases](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#use-cases)
 * [Practical demos](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#practical-demos)
    - [Demo 1: File system operations](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-1-file-system-operations)
    - [Demo 2: SQLite database operations](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-2-sqlite-database-operations)
    - [Demo 3: Processing uploaded files (ZIP archives)](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-3-processing-uploaded-files-zip-archives)
    - [Demo 4: HTTP request/response pattern](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-4-http-request-response-pattern)
    - [Demo 5: Template rendering engine](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-5-template-rendering-engine)
    - [Demo 6: Real-time code execution and streaming](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-6-real-time-code-execution-and-streaming)
 * [Integration patterns](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#integration-patterns)
    - [Pattern 1: Express.js middleware](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#pattern-1-express-js-middleware)
    - [Pattern 2: Automated testing](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#pattern-2-automated-testing)
    - [Pattern 3: Build tool integration](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#pattern-3-build-tool-integration)
 * [Advanced features](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#advanced-features)
    - [Working with environment variables](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#working-with-environment-variables)
    - [Error handling](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#error-handling)
 * [Performance considerations](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#performance-considerations)

[ Back to top](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#wp--skip-link--target)

As a WebAssembly project, you can also use WordPress Playground in Node.js.

If you need low-level control over the underlying WebAssembly PHP build, take a 
look at the [@php-wasm/node package](https://npmjs.org/@php-wasm/node) which ships
the PHP WebAssembly runtime. This package is at the core of all WordPress Playground
tools for Node.js.

Consult the [complete list](https://developer.wordpress.org/playground/api/node)
of Classes, Functions, Interfaces, and Type Aliases.

## 󠀁[WebAssembly PHP for Node.js](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#webassembly-php-for-node-js)󠁿

This package ships WebAssembly PHP binaries and the JavaScript API optimized for
Node.js. It uses the host file system directly and can access the network if you
plug in a custom WS proxy.

### 󠀁[Basic usage](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#basic-usage)󠁿

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));
    const output = await php.runStream({
        code: '<?php phpinfo(); ?>',
    });
    console.log(await output.stdoutText);
    ```

### 󠀁[Loading PHP extensions](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#loading-php-extensions)󠁿

Use the `extensions` loader option to enable optional extensions before PHP
 starts:

    ```javascript
    const php = new PHP(
        await loadNodeRuntime('8.4', {
            extensions: ['intl', 'redis', 'memcached', { name: 'xdebug', options: { ideKey: 'PLAYGROUND' } }],
        })
    );
    ```

The same array can load external JSPI `.so` artifacts from a manifest:

    ```javascript
    const php = new PHP(
        await loadNodeRuntime('8.4', {
            extensions: [
                {
                    source: {
                        format: 'manifest',
                        manifestUrl: './dist/wp_mysql_parser/manifest.json',
                    },
                },
            ],
        })
    );
    ```

External extensions require JSPI. Asyncify support is limited to the bundled
 extensions
shipped with the PHP.wasm packages.

See [Loading PHP extensions](https://developer.wordpress.org/playground/developers/apis/javascript-api/php-extensions)

for manifest format, browser usage, sidecar files, and compatibility notes.

## 󠀁[Use cases](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#use-cases)󠁿

Run PHP inside Node.js without a native PHP install. Allow developer to produce 
the following solutions:

 * CI/CD jobs and developer tooling.
 * Support education and WordPress workflows: Power interactive tutorials, sandboxes,
   and coding challenges.
 * Generate content and prototype server behavior.
 * Render HTML using PHP templates, and quickly stand up mock API endpoints to simulate
   requests.

## 󠀁[Practical demos](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#practical-demos)󠁿

We will list some examples using the PHP-WASM package.

### 󠀁[Demo 1: File system operations](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-1-file-system-operations)󠁿

Execute PHP scripts that interact with the file system:

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    // Create directory structure
    php.mkdir('/app/data');

    // Write configuration file
    await php.writeFile(
        '/app/config.json',
        JSON.stringify({
            app: 'MyApp',
            version: '1.0.0',
            debug: true,
        })
    );

    // Create and run PHP script that reads the config
    await php.writeFile(
        '/app/index.php',
        `<?php
    $config = json_decode(file_get_contents('/app/config.json'), true);
    echo "Application: " . $config['app'] . "\\n";
    echo "Version: " . $config['version'] . "\\n";
    echo "Debug Mode: " . ($config['debug'] ? 'ON' : 'OFF') . "\\n";

    // List all files
    echo "\\nFiles in /app:\\n";
    foreach (scandir('/app') as $file) {
        if ($file !== '.' && $file !== '..') {
            echo "  - $file\\n";
        }
    }
    ?>`
    );

    const result = await php.runStream({ scriptPath: '/app/index.php' });
    console.log(await result.stdoutText);
    ```

### 󠀁[Demo 2: SQLite database operations](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-2-sqlite-database-operations)󠁿

Use PHP’s SQLite extension for data storage:

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    // Create directory for database
    php.mkdir('/data');

    // Create database, insert data, and query
    const result = await php.runStream({
        code: `<?php
    // Create/connect to SQLite database
    $db = new SQLite3('/data/app.db');

    // Create table
    $db->exec('CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT UNIQUE NOT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )');

    // Insert sample data
    $stmt = $db->prepare('INSERT INTO users (name, email) VALUES (?, ?)');
    $users = [
        ['Alice Johnson', 'alice@example.com'],
        ['Bob Smith', 'bob@example.com'],
        ['Charlie Davis', 'charlie@example.com']
    ];

    foreach ($users as $user) {
        $stmt->bindValue(1, $user[0]);
        $stmt->bindValue(2, $user[1]);
        $stmt->execute();
    }

    // Query data
    echo "All Users:\\n";
    echo str_repeat('-', 50) . "\\n";
    $results = $db->query('SELECT * FROM users ORDER BY name');
    while ($row = $results->fetchArray(SQLITE3_ASSOC)) {
        echo "ID: {$row['id']} | {$row['name']} ({$row['email']})\\n";
    }

    $db->close();
    ?>`,
    });

    console.log(await result.stdoutText);

    // Database file persists in the virtual file system
    const dbExists = await php.fileExists('/data/app.db');
    console.log('\nDatabase persisted:', dbExists);
    ```

### 󠀁[Demo 3: Processing uploaded files (ZIP archives)](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-3-processing-uploaded-files-zip-archives)󠁿

Process ZIP files using PHP’s Libzip extension:

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    // Create sample files
    php.mkdir('/uploads');
    await php.writeFile('/uploads/readme.txt', 'This is a sample text file');
    await php.writeFile('/uploads/data.json', JSON.stringify({ name: 'Test', version: '1.0' }));

    // Create, process, and extract ZIP archive
    const result = await php.runStream({
        code: `<?php
    // Create ZIP archive
    $zip = new ZipArchive();
    $zip->open('/uploads/archive.zip', ZipArchive::CREATE);
    $zip->addFromString('readme.txt', file_get_contents('/uploads/readme.txt'));
    $zip->addFromString('data.json', file_get_contents('/uploads/data.json'));
    $zip->addFromString('info.txt', 'Created with PHP WASM');
    $zip->close();

    echo "ZIP archive created successfully\\n\\n";

    // Read and display archive contents
    $zip->open('/uploads/archive.zip');
    echo "Archive Contents:\\n";
    echo str_repeat('=', 50) . "\\n";

    for ($i = 0; $i < $zip->numFiles; $i++) {
        $stat = $zip->statIndex($i);
        $size = round($stat['size'] / 1024, 2);
        echo sprintf("%-40s %10s KB\\n", $stat['name'], $size);
    }

    // Extract files
    $zip->extractTo('/uploads/extracted/');
    $zip->close();

    echo "\\nExtracted successfully to /uploads/extracted/\\n";

    // List extracted files
    echo "\\nExtracted Files:\\n";
    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator('/uploads/extracted/')
    );
    foreach ($files as $file) {
        if ($file->isFile()) {
            echo "  " . $file->getPathname() . "\\n";
        }
    }
    ?>`,
    });

    console.log(await result.stdoutText);
    ```

### 󠀁[Demo 4: HTTP request/response pattern](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-4-http-request-response-pattern)󠁿

Simulate web server behavior with request handlers:

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    // Set up a simple API endpoint
    await php.mkdir('/www/api');
    await php.writeFile(
        '/www/api/users.php',
        `<?php
    header('Content-Type: application/json');

    // Parse request
    $method = $_SERVER['REQUEST_METHOD'];
    $input = json_decode(file_get_contents('php://input'), true);

    // Simple routing
    switch ($method) {
        case 'GET':
            echo json_encode([
                'users' => [
                    ['id' => 1, 'name' => 'John Doe'],
                    ['id' => 2, 'name' => 'Jane Smith']
                ]
            ]);
            break;

        case 'POST':
            $name = $input['name'] ?? 'Unknown';
            echo json_encode([
                'success' => true,
                'user' => [
                    'id' => 3,
                    'name' => $name
                ],
                'message' => "User $name created"
            ]);
            break;

        default:
            http_response_code(405);
            echo json_encode(['error' => 'Method not allowed']);
    }
    ?>`
    );

    // Make GET request
    const getResponse = await php.runStream({
        scriptPath: '/www/api/users.php',
        env: {
            REQUEST_METHOD: 'GET',
            SERVER_NAME: 'localhost',
            SERVER_PORT: '80',
        },
    });
    console.log('GET Response:', await getResponse.stdoutText);

    // Make POST request
    const postResponse = await php.runStream({
        scriptPath: '/www/api/users.php',
        env: {
            REQUEST_METHOD: 'POST',
            SERVER_NAME: 'localhost',
            SERVER_PORT: '80',
        },
        body: JSON.stringify({ name: 'Alice Wonder' }),
    });
    console.log('\\nPOST Response:', await postResponse.stdoutText);
    ```

### 󠀁[Demo 5: Template rendering engine](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-5-template-rendering-engine)󠁿

Use PHP as a templating engine for dynamic content:

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    // Create templates directory
    php.mkdir('/templates');

    // Create template
    await php.writeFile(
        '/templates/email.php',
        `<!DOCTYPE html>
    <html>
    <head>
        <style>
            body { font-family: Arial, sans-serif; }
            .header { background: #4CAF50; color: white; padding: 20px; }
            .content { padding: 20px; }
            .footer { background: #f1f1f1; padding: 10px; text-align: center; }
        </style>
    </head>
    <body>
        <div class="header">
            <h1>Welcome, <?= htmlspecialchars($name) ?>!</h1>
        </div>
        <div class="content">
            <p>Thank you for registering with <?= $appName ?>.</p>
            <p>Your account details:</p>
            <ul>
                <li><strong>Email:</strong> <?= htmlspecialchars($email) ?></li>
                <li><strong>Member Since:</strong> <?= date('F j, Y', $timestamp) ?></li>
            </ul>
            <p>You now have access to the following features:</p>
            <ul>
                <?php foreach ($features as $feature): ?>
                    <li><?= htmlspecialchars($feature) ?></li>
                <?php endforeach; ?>
            </ul>
        </div>
        <div class="footer">
            <p>&copy; <?= date('Y') ?> <?= $appName ?>. All rights reserved.</p>
        </div>
    </body>
    </html>`
    );

    // Render template with data
    const templateData = {
        name: 'Priya Sharma',
        email: 'priya@example.com',
        appName: 'MyAwesomeApp',
        timestamp: Math.floor(Date.now() / 1000),
        features: ['Dashboard Access', 'API Integration', 'Premium Support', 'Custom Branding'],
    };

    // Pass data to template via environment variables or files
    await php.writeFile('/template-data.json', JSON.stringify(templateData));

    const result = await php.runStream({
        code: `<?php
        $data = json_decode(file_get_contents('/template-data.json'), true);
        extract($data);
        include '/templates/email.php';
      ?>`,
    });

    console.log(await result.stdoutText);
    // Now you have rendered HTML that can be sent via email or saved
    ```

### 󠀁[Demo 6: Real-time code execution and streaming](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#demo-6-real-time-code-execution-and-streaming)󠁿

Process PHP output as it’s generated:

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    await php.writeFile(
        '/stream-demo.php',
        `<?php
    // Simulate long-running process
    echo "Starting process...\\n";
    flush();

    for ($i = 1; $i <= 10; $i++) {
        echo "Processing item $i/10...\\n";
        flush();
        usleep(100000); // Sleep 100ms
    }

    echo "Process complete!\\n";
    ?>`
    );

    // Run PHP script
    const streamedResponse = await php.runStream({
        scriptPath: '/stream-demo.php',
    });

    streamedResponse.stdout.pipeTo(
        new WritableStream({
            write(chunk) {
                console.log(chunk);
            },
        })
    );
    ```

## 󠀁[Integration patterns](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#integration-patterns)󠁿

### 󠀁[Pattern 1: Express.js middleware](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#pattern-1-express-js-middleware)󠁿

Integrate PHP processing into an Express.js application:

    ```language-TypeScript
    const app = express();
    const php = new PHP(await loadNodeRuntime('8.3'));

    // PHP execution middleware
    app.use('/php', async (req, res, next) => {
        try {
            const phpScript = req.query.script || 'index.php';
            const result = await php.runStream({
                scriptPath: `/www/${phpScript}`,
                env: {
                    REQUEST_METHOD: req.method,
                    QUERY_STRING: new URLSearchParams(
                        req.query as Record<string, string>
                    ).toString(),
                    REQUEST_URI: req.url,
                },
            });

            res.send(await result.stdoutText);
        } catch (error) {
            next(error);
        }
    });

    app.listen(3000, () => {
        console.log('Server with PHP support running on port 3000');
    });
    ```

### 󠀁[Pattern 2: Automated testing](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#pattern-2-automated-testing)󠁿

Create automated tests for PHP code:

    ```language-TypeScript
    describe('PHP Functions', () => {
        let php: PHP;

        beforeAll(async () => {
            php = new PHP(await loadNodeRuntime('8.3'));
        });

        it('should calculate sum correctly', async () => {
            const result = await php.run({
                code: `<?php
            function sum($a, $b) {
              return $a + $b;
            }
            echo sum(5, 3);
          ?>`,
            });

            expect(result.text).toBe('8');
        });

        it('should handle JSON operations', async () => {
            const input = { name: 'Test', value: 42 };
            const result = await php.run({
                code: `<?php
            $input = json_decode('${JSON.stringify(input)}', true);
            $output = [
              'received' => $input,
              'doubled' => $input['value'] * 2
            ];
            echo json_encode($output);
          ?>`,
            });

            const output = JSON.parse(result.text);
            expect(output.doubled).toBe(84);
        });
    });
    ```

### 󠀁[Pattern 3: Build tool integration](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#pattern-3-build-tool-integration)󠁿

Use in build scripts with other Node.js tools:

    ```javascript
    async function generateDocumentation() {
        const php = new PHP(await loadNodeRuntime('8.3'));

        // Create output directory
        php.mkdir('/output');

        // Generate documentation
        const result = await php.runStream({
            code: `<?php
    echo "Generating documentation...\\n";

    $summary = "# Generated Documentation\\n\\n";
    $summary .= "Generated at: " . date('Y-m-d H:i:s') . "\\n\\n";

    file_put_contents('/output/summary.md', $summary);
    echo "Documentation generated successfully!\\n";
    ?>`,
        });

        console.log(await result.stdoutText);

        // Extract generated docs back to Node.js file system
        await fs.mkdir('./docs', { recursive: true });
        const summaryContent = await php.readFileAsText('/output/summary.md');
        await fs.writeFile('./docs/summary.md', summaryContent);

        console.log('Documentation saved to ./docs/summary.md');
    }

    generateDocumentation().catch(console.error);
    ```

## 󠀁[Advanced features](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#advanced-features)󠁿

### 󠀁[Working with environment variables](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#working-with-environment-variables)󠁿

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    const result = await php.runStream({
        code: '<?php echo getenv("CUSTOM_VAR"); ?>',
        env: {
            CUSTOM_VAR: 'Hello from Node.js!',
        },
    });

    console.log(await result.stdoutText);
    ```

### 󠀁[Error handling](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#error-handling)󠁿

    ```javascript
    const php = new PHP(await loadNodeRuntime('8.3'));

    try {
        const result = await php.runStream({
            code: '<?php trigger_error("Test error", E_USER_ERROR); ?>',
        });

        const stdout = await result.stdoutText;
        const stderr = await result.stderrText;

        console.log('stdout:', stdout);
        console.log('stderr:', stderr);

        if (stderr) {
            console.error('PHP produced errors:', stderr);
        }
    } catch (error: any) {
        console.error('JavaScript Error:', error.message);
    }
    ```

## 󠀁[Performance considerations](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#performance-considerations)󠁿

 * **Reuse PHP instances**: Creating a new PHP instance is expensive. Reuse the 
   same instance when possible.
 * **Batch operations**: Group multiple file operations together rather than running
   separate scripts.
 * **Memory management**: Large files may impact performance. Consider streaming
   for big datasets.
 * **Caching**: Cache compiled PHP scripts and frequently accessed data.

First published

July 15, 2026

Last updated

July 16, 2026

Edit article

[ Improve it on GitHub: Using WordPress Playground in Node.js ](https://raw.githubusercontent.com/WordPress/wordpress-playground/trunk/packages/docs/site/docs/developers/05-local-development/03-php-wasm-node.md)

Changelog

[ See list of changes: Using WordPress Playground in Node.js ](https://developer.wordpress.org/playground/developers/local-development/php-wasm-node/?output_format=md#)

[  Previous: VS Code extension](https://developer.wordpress.org/playground/developers/local-development/vscode-extension/)

[  Next: Debugging with Xdebug in WordPress Playground](https://developer.wordpress.org/playground/developers/xdebug/)