Title: Programmatic Usage of Playground CLI
Published: July 15, 2026
Last modified: July 16, 2026

---

# Programmatic Usage of Playground CLI

## In this article

 * [Running a WordPress instance with a specific version](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#running-a-wordpress-instance-with-a-specific-version)
 * [Setting a blueprint](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#setting-a-blueprint)
 * [Mounting a plugin programmatically](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#mounting-a-plugin-programmatically)
 * [Combining mounts with blueprints](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#combining-mounts-with-blueprints)
 * [Automated testing](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#automated-testing)
    - [Integration testing with Vitest](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#integration-testing-with-vitest)
    - [Testing with different WordPress/PHP versions](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#testing-with-different-wordpress-php-versions)
 * [Advanced configuration](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#advanced-configuration)
    - [Skip WordPress and SQLite setup](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#skip-wordpress-and-sqlite-setup)
    - [Error handling](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#error-handling)

[ Back to top](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#wp--skip-link--target)

The Playground CLI can also be controlled programmatically from your JavaScript/
TypeScript code using the `runCLI` function. This gives you direct access to all
CLI functionalities within your code, which is useful for automating end-to-end 
tests. The options you pass to `runCLI` map directly to the [CLI flags](https://developer.wordpress.org/playground/developers/local-development/wp-playground-cli#command-and-arguments).

## 󠀁[Running a WordPress instance with a specific version](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#running-a-wordpress-instance-with-a-specific-version)󠁿

Using the `runCLI` function, you can specify options like the PHP and WordPress 
versions. In the example below, we request PHP 8.3, the latest version of WordPress,
and to be automatically logged in. All supported arguments are defined in the `RunCLIArgs`
type.

    ```language-TypeScript
    const cliServer = await runCLI({
      command: 'server',
      php: '8.3',
      wp: 'latest',
      login: true,
    });
    ```

Run the code above using your preferred TypeScript runtime, e.g. `tsx`:

    ```language-sh
    npx tsx my-script.ts
    ```

## 󠀁[Setting a blueprint](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#setting-a-blueprint)󠁿

You can provide a blueprint in two ways: either as an object literal directly passed
to the `blueprint` property, or as a string containing the path to an external `.
json` file.

    ```language-TypeScript
    const cliServer: RunCLIServer = await runCLI({
      command: 'server',
      wp: 'latest',
      blueprint: {
        steps: [
            {
              "step": "setSiteOptions",
              "options": {
                  "blogname": "Blueprint Title",
                  "blogdescription": "A great blog description"
              }
            }
        ],
      },
    });
    ```

For full type-safety when defining your blueprint object, you can import and use
the `BlueprintDeclaration` type from the `@wp-playground/blueprints` package:

    ```language-TypeScript
    const myBlueprint: BlueprintDeclaration = {
      landingPage: "/wp-admin/",
      steps: [
        {
          "step": "installTheme",
          "themeData": {
            "resource": "wordpress.org/themes",
            "slug": "twentytwentyone"
          },
          "options": {
            "activate": true
          }
        }
      ]
    };
    ```

## 󠀁[Mounting a plugin programmatically](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#mounting-a-plugin-programmatically)󠁿

You can mount local directories programmatically using `runCLI`. The options `mount`
and `mount-before-install` are available. The `hostPath` property expects a path
to a directory on your local machine. This path should be relative to where your
script is being executed.

    ```language-TypeScript
    const cliServer = await runCLI({
      command: 'server',
      login: true,
      'mount-before-install': [
        {
          hostPath: './[my-plugin-local-path]',
          vfsPath: '/wordpress/wp-content/plugins/my-plugin',
        },
      ],
    });
    ```

## 󠀁[Combining mounts with blueprints](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#combining-mounts-with-blueprints)󠁿

You can combine mounting parts of the project with blueprints, for example:

    ```language-TypeScript
    const cliServer: RunCLIServer = await runCLI({
        command: 'server',
        php: '8.3',
        wp: 'latest',
        login: true,
        mount: [
            {
                "hostPath": "./plugin/",
                "vfsPath": "/wordpress/wp-content/plugins/playwright-test"
            }
        ],
        blueprint: {
            steps: [
                {
                    "step": "activatePlugin",
                    "pluginPath": "/wordpress/wp-content/plugins/playwright-test/plugin-playwright.php"
                }
            ]
        }
    });
    ```

## 󠀁[Automated testing](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#automated-testing)󠁿

### 󠀁[Integration testing with Vitest](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#integration-testing-with-vitest)󠁿

The programmatic API is excellent for automated testing. Here’s a complete example
using Vitest:

    ```language-TypeScript
    describe('My Plugin Tests', () => {
      const cliServer: RunCLIServer;

      afterEach(async () => {
        if (cliServer) {
          // RunCLIServer exposes Symbol.asyncDispose as its public async cleanup API.
          await cliServer[Symbol.asyncDispose]();
        }
      });

      test('plugin activates successfully', async () => {
        cliServer = await runCLI({
          command: 'server',
          mount: [
            {
              hostPath: './my-plugin',
              vfsPath: '/wordpress/wp-content/plugins/my-plugin'
            }
          ],
          blueprint: {
            steps: [
              {
                step: 'activatePlugin',
                pluginPath: '/wordpress/wp-content/plugins/my-plugin/plugin.php'
              }
            ]
          }
        });

        const homeUrl = new URL('/', cliServer.serverUrl);
        const response = await fetch(homeUrl);

        expect(response.status).toBe(200);
        const html = await response.text();
        expect(html).toContain('My Plugin');
      });

      test('plugin settings page loads', async () => {
        cliServer = await runCLI({
          command: 'server',
          login: true, // Auto-login as admin
          mount: [
            {
              hostPath: './my-plugin',
              vfsPath: '/wordpress/wp-content/plugins/my-plugin'
            }
          ],
          blueprint: {
            steps: [
              {
                step: 'activatePlugin',
                pluginPath: '/wordpress/wp-content/plugins/my-plugin/plugin.php'
              }
            ]
          }
        });

        const settingsUrl = new URL(
          '/wp-admin/options-general.php?page=my-plugin',
          cliServer.serverUrl
        );
        const response = await fetch(settingsUrl);

        // Note: A plain `fetch` call does not send the admin session cookie set by `login: true`,
        // so this request is typically redirected to the login page instead of returning 200.
        expect(response.status).toBe(302);
      });
    });
    ```

### 󠀁[Testing with different WordPress/PHP versions](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#testing-with-different-wordpress-php-versions)󠁿

    ```language-TypeScript
    test('plugin works with WordPress 6.4 and PHP 8.3', async () => {
      cliServer = await runCLI({
        command: 'server',
        php: '8.3',
        wp: '6.4',
        mount: [
          {
            hostPath: './my-plugin',
            vfsPath: '/wordpress/wp-content/plugins/my-plugin'
          }
        ],
        blueprint: {
          steps: [
            {
              step: 'activatePlugin',
              pluginPath: '/wordpress/wp-content/plugins/my-plugin/plugin.php'
            }
          ]
        }
      });

      const homeUrl = new URL('/', cliServer.serverUrl);
      const response = await fetch(homeUrl);

      expect(response.status).toBe(200);
    });
    ```

## 󠀁[Advanced configuration](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#advanced-configuration)󠁿

### 󠀁[Skip WordPress and SQLite setup](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#skip-wordpress-and-sqlite-setup)󠁿

When you only need to test PHP code without WordPress, you can skip the setup for
faster testing:

    ```language-TypeScript
    const cliServer = await runCLI({
        command: 'server',
        php: '8.3',
        wordpressInstallMode: 'do-not-attempt-installing',
        skipSqliteSetup: true,
    });

    // Test PHP version
    await cliServer.playground.writeFile(
      '/wordpress/version.php',
      '<?php echo phpversion(); ?>'
    );

    const versionUrl = new URL('/version.php', cliServer.serverUrl);
    const response = await fetch(versionUrl);
    const version = await response.text();
    console.log('PHP Version:', version); // Outputs: 8.3.x
    ```

### 󠀁[Error handling](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#error-handling)󠁿

    ```language-TypeScript
    try {
      const cliServer = await runCLI({
        command: 'server',
        debug: true, // Enable PHP error logging.
      });

      // Your test code here

    } catch (error) {
      console.error('Server failed to start:', error);
    }
    ```

First published

July 15, 2026

Last updated

July 16, 2026

Edit article

[ Improve it on GitHub: Programmatic Usage of Playground CLI ](https://raw.githubusercontent.com/WordPress/wordpress-playground/trunk/packages/docs/site/docs/main/guides/programmatic-playground-cli.md)

Changelog

[ See list of changes: Programmatic Usage of Playground CLI ](https://developer.wordpress.org/playground/handbook/guides/programmatic-playground-cli/?output_format=md#)

[  Previous: WordPress Playground for Everyone](https://developer.wordpress.org/playground/handbook/guides/playground-for-everyone/)

[  Next: Running PHPUnit with the Playground CLI](https://developer.wordpress.org/playground/handbook/guides/phpunit-testing/)