diff --git a/baton/baton-runner-windows.mdx b/baton/baton-runner-windows.mdx
new file mode 100644
index 0000000..0c1ff03
--- /dev/null
+++ b/baton/baton-runner-windows.mdx
@@ -0,0 +1,214 @@
+---
+title: Run multiple connectors as a Windows service
+og:title: Run multiple connectors as a Windows service - ConductorOne docs
+og:description: Install and configure baton-runner as a Windows service to run multiple Baton connectors from a single process on Windows Server.
+description: Install and configure baton-runner as a Windows service to run multiple Baton connectors from a single process on Windows Server.
+sidebarTitle: Run multiple connectors on Windows
+---
+
+{/* Editor Refresh: 2026-03-02 */}
+
+This guide walks through installing baton-runner as a Windows service and configuring it to sync two SQL Server connectors. For a full reference on configuration options and secret backends, see [Baton-runner configuration reference](/baton/baton-runner).
+
+## Before you begin
+
+You'll need:
+
+- A Windows Server with an account that has administrator rights to install Windows services and run administrative PowerShell sessions
+- Usernames and passwords for each SQL Server instance you want to sync
+- The [baton-sql-server](https://github.com/ConductorOne/baton-sql-server) executable downloaded
+- The baton-runner installer downloaded
+- A ConductorOne connector created for each SQL Server instance — see [Deploy self-hosted connectors](/baton/deploy)
+- A client ID and secret for each connector
+
+## Install baton-runner
+
+
+
+Run the baton-runner installer. Right-click the installer and select **Run as administrator** if prompted.
+
+
+The installer completes silently — it does not display progress or require any configuration input.
+
+
+
+Confirm the service installed correctly. Open **Services** (search for "Services" in the Windows search bar) and look for **baton-runner** in the list.
+
+The startup type defaults to **Manual** — leave it as Manual for now.
+
+
+
+
+
+
+Open the baton-runner service properties and select the **Log On** tab. Set the service account to the user account you'll use to store credentials in Windows Credential Manager. This must be the same account you'll use in the wincred steps below.
+
+
+
+
+
+
+
+## Set up connector files
+
+
+
+Create a directory for the baton-sql-server executable. The directory path must not contain spaces.
+
+
+Using File Explorer, navigate to `C:\ProgramData\ConductorOne\baton-runner`.
+
+
+Create a YAML file for each SQL Server instance you want to sync, plus a `config.yaml` file for baton-runner. Name each connector file in a way that identifies the server it connects to.
+
+For this example, we'll use `sql1.yaml` and `sql2.yaml` for two SQL Server instances.
+
+
+
+
+
+
+Open each connector YAML file in Notepad and add the following, replacing the values with the connection string and ConductorOne credentials for that instance:
+
+```yaml
+BATON_DSN: server=192.168.1.40;user id=sa;password=YOUR_PASSWORD;port=1434
+BATON_CLIENT_ID: YOUR_CLIENT_ID
+BATON_CLIENT_SECRET: YOUR_CLIENT_SECRET
+```
+
+
+
+## Store credentials in Windows Credential Manager
+
+Baton-runner uses Windows Credential Manager (wincred) to store connector secrets securely on the server.
+
+
+
+Open PowerShell as administrator. Right-click the Windows logo and select **Windows PowerShell (Admin)**.
+
+
+Change to the baton-runner directory:
+
+```powershell
+cd C:\ProgramData\ConductorOne\baton-runner\
+```
+
+
+Store the credentials for each connector using the `wincred set` command:
+
+```powershell
+& "C:\Program Files (x86)\ConductorOne\baton-runner\baton-runner.exe" wincred set sql1 sql1.yaml
+& "C:\Program Files (x86)\ConductorOne\baton-runner\baton-runner.exe" wincred set sql2 sql2.yaml
+```
+
+Each command should return `successfully set secret.`
+
+
+Verify the credentials are stored. Run:
+
+```powershell
+cmdkey /list
+```
+
+You should see an entry for each connector:
+
+```
+Currently stored credentials:
+
+ Target: LegacyGeneric:target=sql2
+ Type: Generic
+ Local machine persistence
+
+ Target: LegacyGeneric:target=sql1
+ Type: Generic
+ Local machine persistence
+```
+
+You can also verify a specific credential using baton-runner:
+
+```powershell
+& "C:\Program Files (x86)\ConductorOne\baton-runner\baton-runner.exe" wincred get sql1
+```
+
+
+
+## Configure baton-runner
+
+
+
+Open `config.yaml` in `C:\ProgramData\ConductorOne\baton-runner` and add the following configuration, updating the paths and names to match your setup:
+
+```yaml
+connectors:
+ - name: sql1
+ path: C:\baton-sql\baton-sql-server.exe
+ config:
+ envFrom:
+ secrets:
+ BATON_DSN: sql1:BATON_DSN
+ BATON_CLIENT_ID: sql1:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: sql1:BATON_CLIENT_SECRET
+ - name: sql2
+ path: C:\baton-sql\baton-sql-server.exe
+ config:
+ envFrom:
+ secrets:
+ BATON_DSN: sql2:BATON_DSN
+ BATON_CLIENT_ID: sql2:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: sql2:BATON_CLIENT_SECRET
+secrets:
+ wincred:
+ secrets:
+ sql1: sql1
+ sql2: sql2
+```
+
+
+Test the configuration by running baton-runner from PowerShell. Press **Ctrl+C** to stop it once you've confirmed it starts without errors:
+
+```powershell
+& "C:\Program Files (x86)\ConductorOne\baton-runner\baton-runner.exe" -c .\config.yaml
+```
+
+
+
+## Start and validate the service
+
+
+
+Reboot the server. This confirms that the wincred credentials persist across reboots and completes post-installation steps for the service.
+
+
+After rebooting, confirm your credentials are still present:
+
+```powershell
+cmdkey /list
+```
+
+
+Open **Services**, find baton-runner, and click **Start**. Confirm the status changes to **Running**.
+
+
+
+
+
+
+Check the log for errors:
+
+```
+C:\ProgramData\ConductorOne\baton-runner\baton-runner.log
+```
+
+
+In ConductorOne, confirm the connectors are syncing. Navigate to each connector and verify data is appearing.
+
+
+Once syncing is confirmed, change the baton-runner service startup type to **Automatic**.
+
+
+Restart the server one final time to confirm the service starts automatically and all connectors sync successfully.
+
+
+After confirming baton-runner starts successfully and both connectors sync, delete or securely clear the connector YAML files (`sql1.yaml`, `sql2.yaml`) immediately. These files contain plaintext credentials and are no longer needed once secrets are stored in wincred.
+
+
diff --git a/baton/baton-runner.mdx b/baton/baton-runner.mdx
new file mode 100644
index 0000000..d432983
--- /dev/null
+++ b/baton/baton-runner.mdx
@@ -0,0 +1,291 @@
+---
+title: Baton-runner configuration reference
+og:title: Baton-runner configuration reference - ConductorOne docs
+og:description: Configure baton-runner to run multiple Baton connectors from a single process, with support for multiple secret backends.
+description: Configure baton-runner to run multiple Baton connectors from a single process, with support for multiple secret backends.
+sidebarTitle: Baton-runner reference
+---
+
+{/* Editor Refresh: 2026-03-03 */}
+
+[Baton-runner](https://github.com/ConductorOne/baton-runner) runs multiple Baton connectors from a single process. Instead of managing each connector individually, you define all your connectors and their credentials in one `config.yaml` file and run them together.
+
+## Download
+
+Download baton-runner from [dist.conductorone.com/ConductorOne/baton-runner](https://dist.conductorone.com/ConductorOne/baton-runner). Builds are available for Windows (amd64), macOS (amd64 and arm64), and Linux (amd64 and arm64).
+
+For step-by-step setup instructions on Windows Server, see [Run multiple connectors as a Windows service](/baton/baton-runner-windows).
+
+## Configuration
+
+Baton-runner is configured with a single YAML file. By default it looks for `config.yaml` in the current directory. Use the `-c` flag to specify a different path:
+
+```bash
+baton-runner -c /path/to/config.yaml
+```
+
+A `config.yaml` has three top-level keys: `log-level`, `connectors`, and `secrets`.
+
+```yaml
+log-level: info
+
+connectors:
+ - name: github-org1
+ path: /usr/local/bin/baton-github
+ config:
+ envFrom:
+ secrets:
+ BATON_TOKEN: org1:BATON_TOKEN
+ BATON_CLIENT_ID: org1:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: org1:BATON_CLIENT_SECRET
+
+ - name: github-org2
+ path: /usr/local/bin/baton-github
+ config:
+ env:
+ BATON_ORGS: my-org
+ envFrom:
+ secrets:
+ BATON_TOKEN: org2:BATON_TOKEN
+ BATON_CLIENT_ID: org2:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: org2:BATON_CLIENT_SECRET
+
+secrets:
+ insecure:
+ secrets:
+ org1: org1.yaml
+ org2: org2.yaml
+```
+
+### Real-world example
+
+Here's what a production config looks like when running multiple config-driven connectors of the same type — in this case, several SQL Server databases and two HTTP API applications, each with its own connector-specific config file:
+
+```yaml
+log-level: info
+
+connectors:
+ - name: Database_01
+ path: C:\ConductorOne\baton-sql.exe
+ config:
+ env:
+ BATON_CONFIG_PATH: C:\ConductorOne\Database_01.yaml
+ BATON_FILE: C:\ConductorOne\Database_01.c1z
+ BATON_PROVISIONING: true
+ envFrom:
+ secrets:
+ DB_PASSWORD: Database_01:DB_PASSWORD
+ BATON_CLIENT_ID: Database_01:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: Database_01:BATON_CLIENT_SECRET
+
+ - name: Database_02
+ path: C:\ConductorOne\baton-sql.exe
+ config:
+ env:
+ BATON_CONFIG_PATH: C:\ConductorOne\Database_02.yaml
+ BATON_FILE: C:\ConductorOne\Database_02.c1z
+ BATON_PROVISIONING: true
+ envFrom:
+ secrets:
+ DB_PASSWORD: Database_02:DB_PASSWORD
+ BATON_CLIENT_ID: Database_02:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: Database_02:BATON_CLIENT_SECRET
+
+ - name: HTTP_API_App_01
+ path: C:\ConductorOne\baton-http.exe
+ config:
+ env:
+ BATON_CONFIG_PATH: C:\ConductorOne\HTTP_API_App_01.yaml
+ BATON_FILE: C:\ConductorOne\HTTP_API_App_01.c1z
+ BATON_PROVISIONING: true
+ envFrom:
+ secrets:
+ DB_PASSWORD: HTTP_API_App_01:DB_PASSWORD
+ BATON_CLIENT_ID: HTTP_API_App_01:BATON_CLIENT_ID
+ BATON_CLIENT_SECRET: HTTP_API_App_01:BATON_CLIENT_SECRET
+
+secrets:
+ wincred:
+ secrets:
+ Database_01: Database_01
+ Database_02: Database_02
+ HTTP_API_App_01: HTTP_API_App_01
+```
+
+A few patterns to note:
+- `BATON_CONFIG_PATH` points each connector to its own config file, which is how config-driven connectors like `baton-sql` and `baton-http` handle per-instance settings.
+- `BATON_FILE` gives each connector a unique output path so sync files don't overwrite each other.
+- `BATON_PROVISIONING: true` enables write-back provisioning for each connector.
+
+### Connector options
+
+| Field | Required | Description |
+| :--- | :--- | :--- |
+| `name` | Yes | A display name for the connector. Used in logs. |
+| `path` | Yes | Absolute path to the connector executable. |
+| `config.env` | No | Static environment variables passed to the connector as key-value pairs. |
+| `config.envFrom.secrets` | No | Environment variables populated from a secret backend. See [Secret reference format](#secret-reference-format). |
+
+### Secret reference format
+
+Values in `config.envFrom.secrets` use the format `secretname:FIELD`:
+
+- `secretname` — the name defined in the `secrets` section of `config.yaml`
+- `FIELD` — the key to retrieve from within that secret
+
+For example, `org1:BATON_TOKEN` reads the `BATON_TOKEN` field from the secret named `org1`.
+
+## Secret backends
+
+Baton-runner supports multiple backends for storing connector credentials. You can define one backend per `config.yaml`, and all connectors in that file share it.
+
+| Backend | Best for |
+| :--- | :--- |
+| [`wincred`](#windows-credential-manager-wincred) | Windows Server deployments |
+| [`insecure`](#insecure-yaml-files) | Local development and testing only |
+| [`awssecretmanager`](#aws-secrets-manager) | AWS-hosted environments |
+| [`vault`](#hashicorp-vault) | HashiCorp Vault environments |
+
+### Windows Credential Manager (wincred)
+
+Stores credentials in the Windows Credential Manager. Recommended for Windows Server deployments.
+
+The `secrets` map associates a connector secret name with its target name in Windows Credential Manager.
+
+```yaml
+secrets:
+ wincred:
+ secrets:
+ org1: org1
+ org2: org2
+```
+
+Use the `wincred set` command to load credentials into the store:
+
+```powershell
+baton-runner.exe wincred set org1 org1.yaml
+```
+
+Where `org1.yaml` is a YAML file containing the connector's environment variables. See [Run multiple connectors as a Windows service](/baton/baton-runner-windows) for a full walkthrough.
+
+### Insecure (YAML files)
+
+
+The insecure backend stores credentials in plaintext YAML files on disk. Use it for local development and testing only — not in production.
+
+
+The `secrets` map associates a connector secret name with the path to its YAML file.
+
+```yaml
+secrets:
+ insecure:
+ secrets:
+ org1: org1.yaml
+ org2: org2.yaml
+```
+
+Each YAML file contains the connector's environment variables as key-value pairs:
+
+```yaml
+# org1.yaml
+BATON_TOKEN: your-token
+BATON_CLIENT_ID: your-client-id
+BATON_CLIENT_SECRET: your-client-secret
+```
+
+### AWS Secrets Manager
+
+Reads credentials from AWS Secrets Manager. AWS credentials are loaded from the [default credential chain](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html) (environment variables, shared credentials file, IAM role, and so on) — no AWS credentials are configured in `config.yaml` itself.
+
+The `secrets` map associates a connector secret name with the path to a YAML pointer file:
+
+```yaml
+secrets:
+ awssecretmanager:
+ secrets:
+ org1: org1-aws.yaml
+```
+
+Each pointer file specifies the AWS secret name and region:
+
+```yaml
+# org1-aws.yaml
+secretname: my-conductorone-org1-secret
+region: us-east-1
+```
+
+The secret value stored in AWS Secrets Manager must be a JSON or YAML string containing the connector's environment variables as key-value pairs.
+
+### HashiCorp Vault
+
+Reads credentials from a HashiCorp Vault KV secrets engine. Both KV v1 and v2 are supported.
+
+```yaml
+secrets:
+ vault:
+ url: https://vault.example.com:8200
+ mount: secret
+ kvapi: 2
+ credsfile: vaultcreds.yaml
+ secrets:
+ org1: conductorone/org1
+ org2: conductorone/org2
+```
+
+The `secrets` map associates a connector secret name with the KV path in Vault.
+
+**Authentication** — specify credentials using one of these options (listed in priority order):
+
+| Option | How |
+| :--- | :--- |
+| Credential file | Set `credsfile` to the path of a YAML file containing `token`, or `username` and `password` |
+| Inline token | Set `token` directly in `config.yaml` |
+| Inline username/password | Set `username` and `password` directly in `config.yaml` |
+
+Credential file format:
+
+```yaml
+# vaultcreds.yaml — use either token or username/password
+token: your-vault-token
+```
+
+```yaml
+# vaultcreds.yaml
+username: your-username
+password: your-password
+```
+
+{/*
+### Delinea Secret Server
+
+Reads credentials from Delinea (formerly Thycotic) Secret Server. Supports both username/password and NTLM authentication.
+
+The `secrets` map associates a connector secret name with the integer Secret ID in Secret Server.
+
+```yaml
+secrets:
+ secretserver:
+ url: https://secretserver.example.com
+ username: service-account # omit to use NTLM authentication
+ password: your-password
+ secrets:
+ org1: "12345" # Secret Server secret ID
+ org2: "12346"
+```
+
+If `username` and `password` are omitted, baton-runner uses NTLM authentication.
+*/}
+
+## Log level
+
+Set the log level using the `log-level` key in `config.yaml` or the `BATON_LOG_LEVEL` environment variable. Valid values: `debug`, `info`, `warn`, `error`, `panic`. The default is `info`.
+
+```yaml
+# In config.yaml
+log-level: debug
+```
+
+```bash
+# As an environment variable
+BATON_LOG_LEVEL=debug baton-runner -c config.yaml
+```
diff --git a/docs.json b/docs.json
index e1754ff..4e12c84 100644
--- a/docs.json
+++ b/docs.json
@@ -269,6 +269,8 @@
"group": "Deploy connectors",
"pages": [
"baton/deploy",
+ "baton/baton-runner-windows",
+ "baton/baton-runner",
"baton/health-checks"
]
},
diff --git a/images/product/assets/baton-runner-windows-1.png b/images/product/assets/baton-runner-windows-1.png
new file mode 100644
index 0000000..55c57df
Binary files /dev/null and b/images/product/assets/baton-runner-windows-1.png differ
diff --git a/images/product/assets/baton-runner-windows-2.png b/images/product/assets/baton-runner-windows-2.png
new file mode 100644
index 0000000..16787bc
Binary files /dev/null and b/images/product/assets/baton-runner-windows-2.png differ
diff --git a/images/product/assets/baton-runner-windows-3.png b/images/product/assets/baton-runner-windows-3.png
new file mode 100644
index 0000000..9570dea
Binary files /dev/null and b/images/product/assets/baton-runner-windows-3.png differ
diff --git a/images/product/assets/baton-runner-windows-4.png b/images/product/assets/baton-runner-windows-4.png
new file mode 100644
index 0000000..821623e
Binary files /dev/null and b/images/product/assets/baton-runner-windows-4.png differ