# Advice for running Appium in Azure DevOps Pipelines

**URL:** <https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978>\
**Category:** Support\
**Created:** [August 25, 2025, 8:00am UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978 "2025-08-25T08:00:11Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ALPA-Industry-and-Te](https://discuss.appium.io/user_avatar/discuss.appium.io/alpa-industry-and-te/32/14295_2.png) [@ALPA-Industry-and-Te](https://discuss.appium.io/u/ALPA-Industry-and-Te)\
**Post date:** [August 25, 2025, 8:00am UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978/1 "2025-08-25T08:00:11Z")

</div>

Hi everyone,

I’m currently working on setting up **Appium in an Azure DevOps pipeline** and I’d love to hear your advice or best practices.

Right now, I’m discussing what’s the “right” way to start Appium inside a pipeline step.

For example:

`script: |`  
`echo “Installing Appium…”`  
`npm install -g appium`  
`echo “Starting Appium…”`  
`appium --log-level info 2>&1 | tee appium.log &`  
`sleep 10`  
`displayName: ‘Start Appium Server’`

versus

`script: |`  
`echo “Installing Appium…”`  
`npm install -g appium`  
`echo “Starting Appium…”`  
`nohup appium --log-level info 2>&1 | tee appium.log &`  
`sleep 10`  
`displayName: ‘Start Appium Server’`

Both approaches seem to work, but I’m unsure which one is more reliable in the Azure DevOps hosted agent environment.

👉 Do you have any recommendations or experiences with:

- The best way to run Appium in Azure Pipelines?

- Ensuring the Appium server stays alive during the test job?

- Managing logs (console + log file)?

- Running multiple Appium servers in parallel jobs?

- How the `options` block and `appium_server_url` should be configured in a Python test script when running in the pipeline?

In my local environment this worked quite nicely:

```python
capabilities = dict(platformName=‘Android’,automationName=‘uiautomator2’,deviceName=‘Android’,appPackage=‘com.android.settings’,appActivity=‘.Settings’,language=‘en’,locale=‘US’)

```

```python
appium_server_url = ‘http://localhost:4723’

```

Any advice, lessons learned, or gotchas would be super helpful.

Thanks a lot!

Best,  
Alex

---

<div class="post-metadata">

**Author:** ![mykola-mokhnach](https://discuss.appium.io/user_avatar/discuss.appium.io/mykola-mokhnach/32/4578_2.png) [@mykola-mokhnach](https://discuss.appium.io/u/mykola-mokhnach)\
**Post date:** [August 25, 2025, 4:55pm UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978/2 "2025-08-25T16:55:06Z")

</div>

Both approaches are suboptimal. There should be no hardcoded sleep after starting the server. Consider waiting until it replies to /status request with the given timeout:

```bash
HOST="localhost"
PORT="4723"
TIMEOUT="15"
URL="http://${HOST}:${PORT}/status"
INTERVAL=1 # seconds between retries

# Track time
START_TIME=$(date +%s)

echo "Checking service at $URL for up to $TIMEOUT seconds..."

while true; do
  HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$URL")

  if [["$HTTP_STATUS" -eq 200]]; then
    echo "Service is running on ${HOST}:${PORT} (HTTP 200)"
    exit 0
  fi

  CURRENT_TIME=$(date +%s)
  ELAPSED=$((CURRENT_TIME - START_TIME))

  if [["$ELAPSED" -ge "$TIMEOUT"]]; then
    echo "Timeout reached: Service is NOT running on ${HOST}:${PORT} (Last status: HTTP $HTTP_STATUS)"
    exit 1
  fi

  sleep "$INTERVAL"
done

```

---

<div class="post-metadata">

**Author:** ![ALPA-Industry-and-Te](https://discuss.appium.io/user_avatar/discuss.appium.io/alpa-industry-and-te/32/14295_2.png) [@ALPA-Industry-and-Te](https://discuss.appium.io/u/ALPA-Industry-and-Te)\
**Post date:** [August 27, 2025, 6:59am UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978/3 "2025-08-27T06:59:32Z")

</div>

Thanks a lot!  
Is `nohup appium --log-level info > appium.log 2>&1 &` a good approach for starting Appium in the background?

```python
  - script: |
      nohup appium --log-level info > appium.log 2>&1 &

      HOST="localhost"
      PORT="4723"
      TIMEOUT=15
      URL="http://${HOST}:${PORT}/status"
      INTERVAL=1

      echo "Waiting for Appium to be ready at $URL ..."

      START_TIME=$(date +%s)

      while true; do
        HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$URL")

        if [["$HTTP_STATUS" -eq 200]]; then
          echo "✅ Appium is running on ${HOST}:${PORT}"
          break
        fi

        CURRENT_TIME=$(date +%s)
        ELAPSED=$((CURRENT_TIME - START_TIME))

        if [["$ELAPSED" -ge "$TIMEOUT"]]; then
          echo "❌ Timeout reached: Appium did not start on ${HOST}:${PORT}"
          exit 1
        fi

        sleep "$INTERVAL"
      done
    displayName: "Start Appium"

```

---

<div class="post-metadata">

**Author:** ![mykola-mokhnach](https://discuss.appium.io/user_avatar/discuss.appium.io/mykola-mokhnach/32/4578_2.png) [@mykola-mokhnach](https://discuss.appium.io/u/mykola-mokhnach)\
**Post date:** [August 27, 2025, 4:54pm UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978/4 "2025-08-27T16:54:53Z")

</div>

without nohup the process would be killed as soon as the corresponding script step is completed

---

<div class="post-metadata">

**Author:** ![ALPA-Industry-and-Te](https://discuss.appium.io/user_avatar/discuss.appium.io/alpa-industry-and-te/32/14295_2.png) [@ALPA-Industry-and-Te](https://discuss.appium.io/u/ALPA-Industry-and-Te)\
**Post date:** [August 29, 2025, 10:24am UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978/5 "2025-08-29T10:24:26Z")

</div>

Thank you for your answer!

On Ubuntu and macOS, using `nohup` allows the process to keep running after the script step completes. How can I achieve the same behavior on Windows 10 and Windows 11 using PowerShell or CMD?

---

<div class="post-metadata">

**Author:** ![mykola-mokhnach](https://discuss.appium.io/user_avatar/discuss.appium.io/mykola-mokhnach/32/4578_2.png) [@mykola-mokhnach](https://discuss.appium.io/u/mykola-mokhnach)\
**Post date:** [August 29, 2025, 3:28pm UTC](https://discuss.appium.io/t/advice-for-running-appium-in-azure-devops-pipelines/45978/6 "2025-08-29T15:28:21Z")

</div>

Github actions allow to set bash as run shell for Windows as well. If you interested about cmd in particular then this is what ChatGPT proposes:

````auto
Yes, there **is an alternative to the `nohup` command in Windows** , but since Windows and Unix-based systems (like Linux) handle processes differently, the equivalent behavior requires different tools or techniques.

---

## ✅ What `nohup` Does (Quick Reminder):

`nohup` (short for "no hang up") allows you to **run a command or script in the background** , even after the user logs out or the terminal is closed. The output is usually redirected to `nohup.out`.

---

## 🪟 Windows Alternatives to `nohup`

### 1. **`Start-Process` in PowerShell**

This is the most direct alternative. It allows launching a process **independently of the terminal**.

```powershell
Start-Process -FilePath "python" -ArgumentList "my_script.py" -WindowStyle Hidden
```

✅ *The process will continue running even after you close the PowerShell window.*

You can also redirect output:

```powershell
Start-Process -FilePath "python" -ArgumentList "my_script.py > output.log" -NoNewWindow
```

---

### 2. **`start` Command in CMD**

```cmd
start /b python my_script.py > output.log 2>&1
```

* `/b`: runs in background (without a new window)
* `> output.log 2>&1`: redirects both stdout and stderr to a file

⚠️ This method **may still terminate the process when the terminal is closed** — for truly detached execution, PowerShell or Task Scheduler is more reliable.

---

### 3. **Task Scheduler (GUI or `schtasks`)**

You can schedule a script to run **independently of any user session** :

```cmd
schtasks /Create /SC ONCE /TN "MyScript" /TR "C:\Path\To\python.exe C:\Path\To\my_script.py" /ST 12:00
```

Then start it with:

```cmd
schtasks /Run /TN "MyScript"
```

✅ Survives logout, system restarts, etc. Best for **long-running background tasks**.

---

### 4. **Using `pythonw.exe` for Python scripts (No Console Window)**

If you're running a Python script and want **no terminal window at all** :

```cmd
C:\Path\To\pythonw.exe C:\Path\To\my_script.py
```

* Works well for **GUI apps or background scripts**
* **No output or error shown** , so you need to handle logging inside your script

---

### Summary Table:

| Command | Detached? | Logging Support | Best Use |
| ---------------------------- | ------------- | ------------------------------ | -------------------------------- |
| `Start-Process` (PowerShell) | ✅ Yes | ✅ Yes | General background scripts |
| `start /b` (CMD) | ⚠️ Not always | ✅ Yes | Simple tasks, temporary |
| `schtasks` | ✅ Yes | ✅ Yes | Scheduled or persistent tasks |
| `pythonw.exe` | ✅ Yes | ❌ No (unless handled manually) | Silent background Python scripts |

---

````
