# Run locally

> How do I run Windmill scripts locally for testing and debugging?

Windmill has [its own integrated development environment](../../code_editor/index.mdx). But for iteration, integration with CI/CD and testing purposes you may need to run a script locally that also interacts with Windmill (for example, to retrieve resources).
It will allow you to integrate Windmill with any testing framework.

To setup a local development environment for Windmill, see the dedicated [Local development page](./index.mdx).

To run scripts locally, you will need to [fill out the context variables](#interacting-with-windmill-locally) that would otherwise be filled out by the Windmill runtime for you.

### Deno / Bun

Windmill [Deno](https://deno.land/) & [Bun](https://bun.sh/) scripts can be run like normal scripts. To add testing or
debugging code, add this snippet to your file:

```ts
if (import.meta.main) {
	// Add your testing & debugging code here.
}
```

You can then use your script like normal (for example,
`deno run -A --watch my_script.ts` / `bun run --watch my_script.ts`), and even write tests inside.

If you'd like to tweak the client settings more directly, use:

```ts
wmill.setClient(<TOKEN>, <API BASE URL>)
```

On import, the wmill client does the following:

```ts
setClient(
	Deno.env.get('WM_TOKEN') ?? 'no_token',
	Deno.env.get('BASE_INTERNAL_URL') ?? 'http://localhost:8000'
);
```

```ts
setClient(
	process.env.WM_TOKEN ?? 'no_token',
	process.env.BASE_INTERNAL_URL ?? 'http://localhost:8000'
);
```

which is why we recommend setting those environment variables in the [sections below](#interacting-with-windmill-locally).

For more information on Deno & Bun development in general, see their official doc: [Deno](https://deno.land/manual@v1.36.1/getting_started), [Bun](https://bun.sh/docs).

### Python

Windmill Python scripts can be run like normal Python scripts. To add testing or
debug code, add this snippet to your file:

```py
if __name__ == '__main__':
    # Add your testing & debugging code here.
    pass
```

You can then run your script: `python -m f.folder.my_script` and even write tests inside.

For more information on Python development in general,
[see the official docs](https://www.python.org/doc/).

## Interacting with Windmill locally

To interact with Windmill locally, you will need to fill out the context variables that would otherwise be filled out by the Windmill runtime for you.

The most important ones are
`WM_TOKEN`, `WM_WORKSPACE` and `BASE_INTERNAL_URL`.

Set `BASE_INTERNAL_URL` to the URL of you Windmill instance,
for example `https://app.windmill.dev`, note that you can never include a
trailing `/`, or the client will fail to connect. Then set `WM_TOKEN` to a
token, either create this in the UI, or use [wmill, the CLI](../3_cli/index.mdx)
using `wmill user create-token`. And then `WM_WORKSPACE` corresponds to your workspace id.
Below are some examples on how to do this in various environments.

### State

To use the `getState` and `setState` functions, you will have to set `WM_STATE_PATH`. We recommend using your script path name as the state path, for example:

```ts
let fullUrl = import.meta.url;
let pathS = fullUrl.substring(8, fullUrl.length - 3).split('/');
const path = pathS.slice(pathS.length - 3, pathS.length).join('/');
Deno.env.set('WM_STATE_PATH', path);
```

```ts
let fullUrl = import.meta.url;
let pathS = fullUrl.substring(8, fullUrl.length - 3).split('/');
const path = pathS.slice(pathS.length - 3, pathS.length).join('/');
process.env.WM_STATE_PATH = path;
```

### Terminal

On UNIX platforms you can simply do
`BASE_INTERNAL_URL=https://app.windmill.dev WM_TOKEN=ThisIsAToken deno run -A my_script.ts`
with the relevant info provided, the same will work for Python.

On Windows this is not possible, you will have to use
[set](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1).
For example:

```cmd
set "BASE_INTERNAL_URL=https://app.windmill.dev"
set "WM_TOKEN=ThisIsAToken"
set "WM_WORKSPACE=workspace_id"
```

then simply run the relevant command for your language.

### VS Code

:::info VS Code extension

Windmill has its own extension on VS Code for local development & testing, see [VS Code extension](../../cli_local_dev/1_vscode-extension/index.mdx).

:::

To interact with you Windmill instance from VS Code, use a launch.json. See how to create one for
[Python](https://code.visualstudio.com/docs/python/debugging) and
[Deno](https://deno.land/manual@v1.9.2/getting_started/debugging_your_code#vscode).

Then add environment files using the "env" section in your configuration.

:::caution

Make sure you are not checking your Token into git.

To manage your secrets it may be easier to use a .env file, and add it to
.gitignore, this is also done below.

:::

For example, for TypeScript:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Deno",
      "type": "pwa-node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "deno",
      "runtimeArgs": ["run", "--inspect-brk", "-A", "${file}"],
      "env": {
        "BASE_INTERNAL_URL": "https://app.windmill.dev",
        "WM_TOKEN": "ThisIsAToken",
        "WM_WORKSPACE": "workspace_id"
      },
      "envFile": ".env"
    }
  ]
}
```

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Bun",
      "type": "pwa-node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "bun",
      "runtimeArgs": ["run", "${file}"],
      "env": {
        "BASE_INTERNAL_URL": "https://app.windmill.dev",
        "WM_TOKEN": "ThisIsAToken",
        "WM_WORKSPACE": "workspace_id"
      },
      "envFile": ".env"
    }
  ]
}
```

The same `env` & `envFile` options are also supported by Python.

### JetBrains IDEs

Especially for Python you may prefer using a JetBrains IDE. Simply navigate to
your
[run config](https://www.jetbrains.com/help/idea/run-debug-configuration-python.html#1)
and add two lines:

```
BASE_INTERNAL_URL = https://app.windmill.dev
WM_TOKEN = ThisIsAToken
WM_WORKSPACE= workspace_id
```

:::caution

Make sure you are not checking your Token into git.

:::
