Resource library

QA How-To

Appium 3 Config File Setup Tutorial: capabilities and .conf (2026)

Follow this appium 3 config file setup tutorial to create, validate, and use secure server configuration for repeatable local and CI mobile tests.

18 min read | 2,691 words

TL;DR

Create a YAML file with a top-level server object, place Appium server options beneath it, and start Appium with appium --config ./appium.config.yaml. Verify the effective URL and status endpoint before connecting your test runner.

Key Takeaways

  • Put Appium server arguments under the server key in a YAML, JSON, or JavaScript configuration file.
  • Start Appium with --config and confirm the resolved address, port, base path, and log settings in startup output.
  • Keep session capabilities in test code, not in the Appium server configuration file.
  • Use environment variables or CI secrets for sensitive values instead of committing credentials.
  • Resolve relative file paths from the working directory and use explicit paths in CI.
  • Validate YAML syntax and test server readiness before running a mobile suite.

An Appium 3 config file setup tutorial should leave you with one repeatable command, not a collection of shell flags that every engineer remembers differently. Appium can load server arguments from a configuration file, so local machines and CI workers start the same server with the same network, path, logging, and security behavior.

This tutorial builds that configuration from an empty folder, validates it, and connects a real WebdriverIO smoke test. For the wider architecture, driver model, and migration context, read the Appium 3 mobile automation complete guide.

You will use YAML for the main example because it is easy to review. You will also see equivalent JSON and JavaScript formats, safe environment-specific overrides, and failure checks that make configuration errors visible before a test suite begins.

What You Will Build

By the end, you will have:

  • A version-controlled appium.config.yaml with server address, port, base path, logging, and session settings.
  • A package script that starts Appium 3 from that file.
  • A readiness check against the correct Appium status URL.
  • A runnable WebdriverIO test that creates and deletes an Android session.
  • A CI-friendly override pattern that keeps secrets and machine-specific paths outside source control.

The finished layout is deliberately small:

appium-config-demo/
├── appium.config.yaml
├── package.json
└── test/
    └── android-smoke.mjs

The configuration controls the Appium server process. The test file still owns capabilities such as platform name, automation engine, device name, and application path. Keeping those responsibilities separate prevents a server change from silently changing what the test requests.

Prerequisites

Use Node.js 20 LTS or newer and Appium 3 installed as a project dependency. Appium 3 requires a supported modern Node.js release, so confirm the exact engine range printed by your selected Appium package before standardizing a CI image. You also need Java, Android SDK tools, an emulator or device, and the UiAutomator2 driver for the Android verification test.

node --version
npm --version
mkdir appium-config-demo
cd appium-config-demo
npm init -y
npm install --save-dev appium@3 webdriverio
npx appium driver install uiautomator2

Check the installation without depending on a global Appium binary:

npx appium --version
npx appium driver list --installed
adb devices

Expect an Appium version beginning with 3, an installed UiAutomator2 entry, and at least one Android device in the device state. If driver installation is new to you, complete the Appium 3 drivers and plugins CLI tutorial first. Use a real test APK that you are authorized to install, and record its absolute path for Step 6.

Appium 3 Config File Setup Tutorial: Choose a Format

Appium supports configuration through files understood by its configuration loader. YAML is a strong default for static team configuration. JSON is strict and familiar, while JavaScript is useful when configuration genuinely needs programmatic logic. Prefer the least dynamic format that solves the problem.

Format Typical filename Best use Main tradeoff
YAML appium.config.yaml Human-reviewed team defaults Indentation mistakes can change structure
JSON appium.config.json Strict syntax and generated configuration No comments and more punctuation
JavaScript appium.config.js Computed values and Node-based composition Logic can make startup behavior harder to audit

This tutorial uses YAML. Do not put WebDriver capabilities under server. Appium configuration options describe how the server starts. Capabilities are part of the new-session request made by the client.

Step 1: Create the Minimal Appium 3 Server Config File

Create appium.config.yaml in the project root:

server:
  address: 127.0.0.1
  port: 4723
  base-path: /

The top-level server key selects Appium server configuration. Child keys correspond to Appium server command-line arguments. In a file, use the option name without the leading --. The address binds only to the local interface, which is safer for a developer laptop than exposing the service to the network. Port 4723 is Appium's conventional port.

The explicit / base path matters because old examples often assume /wd/hub. Modern Appium uses / unless you deliberately configure another path. Your client and health check must use the same value.

Verify Step 1

Start the server with the local executable:

npx appium --config ./appium.config.yaml

The startup log should show a listener at http://127.0.0.1:4723/. In another terminal, run:

curl --fail --silent http://127.0.0.1:4723/status

Expect a JSON response whose value.ready field is true. Stop the foreground server with Ctrl+C before editing the file. If Appium says the config cannot be found, print pwd and use an absolute path.

Step 2: Add Logging and Session Guardrails

Extend the same file with operational defaults:

server:
  address: 127.0.0.1
  port: 4723
  base-path: /
  log-level: info
  log-timestamp: true
  session-override: false
  strict-caps: true
  default-capabilities: {}

log-level: info gives useful lifecycle details without debug-level volume. Timestamps make local and CI logs comparable. session-override: false prevents a new request from silently deleting an existing session. strict-caps: true makes malformed capability requests fail early instead of being accepted ambiguously. The empty default capabilities object documents that tests, not the server, own session intent.

Use debug temporarily when diagnosing driver startup, then return to info. Avoid enabling session override as a routine solution for leaked sessions. Fix client teardown so every successful new-session request eventually sends delete-session.

Verify Step 2

Run Appium again:

npx appium --config ./appium.config.yaml

Confirm each log line has a timestamp and the server starts without reporting an unknown argument. Send the status request again. A successful status response proves the added options did not prevent startup, but it does not yet prove a driver can create a session.

Step 3: Add a Repeatable npm Command

Edit the generated package.json so the Appium version and startup command are project-owned. A complete minimal file looks like this:

{
  "name": "appium-config-demo",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "appium": "appium --config ./appium.config.yaml",
    "test:android": "node ./test/android-smoke.mjs"
  },
  "devDependencies": {
    "appium": "^3.0.0",
    "webdriverio": "^9.0.0"
  }
}

Keep the versions actually selected by npm install and commit package-lock.json. The example ranges express the required major releases, but your lockfile determines the precise reproducible dependency graph. The npm script automatically resolves node_modules/.bin/appium, so contributors do not need matching global installations.

Run the server through the package script:

npm run appium

Verify Step 3

In a second terminal, inspect which process owns the port and call its status endpoint:

curl --fail http://127.0.0.1:4723/status

The command must exit with status zero. Also run npm ls appium webdriverio and confirm both resolve from this project. If npm reports invalid versions, restore the exact dependency entries produced during installation instead of copying illustrative ranges over newer compatible versions.

Step 4: Configure a Custom Base Path Correctly

Some grids, reverse proxies, and migrated frameworks route Appium under /wd/hub. If your infrastructure requires it, change only the base path:

server:
  address: 127.0.0.1
  port: 4723
  base-path: /wd/hub
  log-level: info
  log-timestamp: true
  session-override: false
  strict-caps: true
  default-capabilities: {}

Start the server and move /status beneath the configured prefix:

npm run appium
curl --fail --silent http://127.0.0.1:4723/wd/hub/status

Your WebDriver client must now set path: '/wd/hub'. A base-path mismatch commonly looks like a healthy server plus a client-side 404. It is a routing problem, not a driver problem. If you do not have a proxy or legacy compatibility requirement, keep / to reduce moving parts.

Verify Step 4

The prefixed status URL should return value.ready: true. Calling http://127.0.0.1:4723/status should no longer be your readiness check. Choose one base path for local and CI environments where possible. If migration forces a temporary difference, expose it as an environment variable in the client rather than duplicating test code.

Step 5: Use Safe Environment-Specific Overrides

Keep stable defaults in YAML and pass small machine-specific differences on the command line. Appium CLI arguments override file values, which makes a port override straightforward:

npx appium --config ./appium.config.yaml --port 4725

For a shell-managed CI port, use:

APPIUM_PORT=4725
npx appium --config ./appium.config.yaml --port "$APPIUM_PORT"

Then verify the overridden endpoint:

curl --fail --silent http://127.0.0.1:4725/wd/hub/status

Do not place cloud access keys, signing passwords, tokens, or service-account JSON in the Appium config. Store them in your CI secret manager and pass them only to the process or test that needs them. Do not print secret-bearing environment variables in diagnostic logs.

If environments differ extensively, create reviewed files such as config/appium.local.yaml and config/appium.ci.yaml, then select one explicitly with --config. Avoid hidden automatic selection based on a developer's machine name.

Verify Step 5

Read the Appium startup URL and ensure it contains port 4725. Confirm port 4723 is unused or belongs to a different intentional process. The status call to 4725 must pass before the test runner starts. This readiness gate separates server startup failures from session creation failures.

Step 6: Connect a Runnable Android Smoke Test

Restore the base path to / for the simplest example, or keep /wd/hub and use the matching client path below. Create test/android-smoke.mjs:

import assert from 'node:assert/strict';
import { remote } from 'webdriverio';

const client = await remote({
  hostname: process.env.APPIUM_HOST ?? '127.0.0.1',
  port: Number(process.env.APPIUM_PORT ?? 4723),
  path: process.env.APPIUM_BASE_PATH ?? '/',
  logLevel: 'info',
  capabilities: {
    platformName: 'Android',
    'appium:automationName': 'UiAutomator2',
    'appium:deviceName': process.env.ANDROID_DEVICE_NAME ?? 'Android',
    'appium:app': process.env.ANDROID_APP_PATH,
    'appium:newCommandTimeout': 120
  }
});

try {
  const sessionId = client.sessionId;
  assert.ok(sessionId, 'Appium did not return a session ID');
  const source = await client.getPageSource();
  assert.ok(source.length > 0, 'The application source was empty');
  console.log(`Created Android session: ${sessionId}`);
} finally {
  await client.deleteSession();
}

Start an emulator, provide an absolute APK path, start Appium, and run the test in another terminal:

export ANDROID_APP_PATH=/absolute/path/to/app-under-test.apk
npm run test:android

The vendor-prefixed appium: capabilities comply with W3C WebDriver rules. The test asserts a session ID and nonempty page source, then always deletes the session. For an already installed application, replace appium:app with the appropriate appium:appPackage and appium:appActivity values for your authorized test target.

Verify Step 6

Expect Created Android session: followed by an ID, an Appium new-session log, and a delete-session log. If the status endpoint passes but session creation fails, inspect the driver log and capabilities. Server configuration has already cleared its verification boundary.

Step 7: Validate Configuration Before CI Tests

Add explicit preflight commands to a CI job. The following POSIX shell sequence starts Appium in the background, records its process ID, waits up to 30 attempts, and cleans up on exit:

set -eu

npm run appium > appium-server.log 2>&1 &
APPIUM_PID=$!
trap 'kill "$APPIUM_PID" 2>/dev/null || true' EXIT INT TERM

i=1
until curl --fail --silent http://127.0.0.1:4723/status > /dev/null; do
  if [ "$i" -ge 30 ]; then
    echo "Appium did not become ready"
    sed -n '1,240p' appium-server.log
    exit 1
  fi
  i=$((i + 1))
  sleep 1
done

npm run test:android

This gate waits for observable readiness rather than sleeping for an assumed startup duration. The trap stops the exact process launched by the job. Preserve appium-server.log as a CI artifact when a test fails, but review logging rules before uploading files that may contain application data.

Add a YAML parser check if your CI image provides one. For example, Ruby ships with many Unix environments, but do not assume it exists without declaring it:

ruby -e 'require "yaml"; YAML.safe_load_file("appium.config.yaml", aliases: false); puts "YAML syntax OK"'

Verify Step 7

Temporarily change the readiness URL to the wrong port in a local copy. The loop should fail, print the server log, and return a nonzero exit code. Restore the correct URL and confirm the Android smoke test runs. Never commit the deliberate failure.

Appium 3 Config File Setup Tutorial: Verify the Final Configuration

For a direct local setup, the finished YAML is:

server:
  address: 127.0.0.1
  port: 4723
  base-path: /
  log-level: info
  log-timestamp: true
  session-override: false
  strict-caps: true
  default-capabilities: {}

The equivalent JSON is useful when tooling generates configuration:

{
  "server": {
    "address": "127.0.0.1",
    "port": 4723,
    "base-path": "/",
    "log-level": "info",
    "log-timestamp": true,
    "session-override": false,
    "strict-caps": true,
    "default-capabilities": {}
  }
}

Start either file explicitly. Do not rely on an engineer's global working directory or an implicitly discovered personal config. Treat the selected format as source code: review changes, explain nonobvious options, and remove settings that no longer serve a current requirement. A concise explicit config is easier to audit than a copied file containing flags nobody can justify. Record the Appium version, Node.js version, installed drivers, selected config path, and effective status URL in CI output. These facts make failed runs reproducible without exposing credentials or relying on undocumented machine state:

npx appium --config "$(pwd)/appium.config.yaml"

Verify Step 8

Clone the project into a clean directory, run npm ci, install the required Appium driver if your environment does not persist the Appium extension home, and execute the readiness plus smoke checks. A clean-clone test catches uncommitted configs, global binary dependencies, and hard-coded paths. For deterministic extensions across machines, follow the Appium 3 driver version management guide.

Troubleshooting

Unable to find configuration file -> Run pwd, list the file, and pass an absolute path to --config. In CI, confirm the checkout step ran and that the job's working directory is the repository root. Filename case matters on Linux.

YAML parses but Appium reports an unknown argument -> Confirm every server option sits beneath server, remove the CLI -- prefix from file keys, and compare the option with npx appium --help for your installed Appium version. Do not copy an option from an unrelated driver into server configuration.

The client receives 404 from a running server -> Match the client's path to base-path. Use / with http://host:4723/status, or /wd/hub with http://host:4723/wd/hub/status. Check proxy path rewriting separately.

Port 4723 is already in use -> Stop the stale process or choose a different explicit port. On macOS and Linux, lsof -nP -iTCP:4723 -sTCP:LISTEN identifies the listener. Do not kill unrelated processes blindly.

Status is ready but new session fails -> Treat this as a driver, device, application, or capability problem. Run npx appium driver list --installed, check adb devices, confirm the APK path, and read the first driver error in the server log. The Appium 2 to Appium 3 migration tutorial explains common framework-level changes.

CI works locally but cannot find a driver -> Appium drivers live in the Appium extension home, separate from ordinary project dependencies unless your workflow installs and pins them. Install the driver in CI, cache the correct extension directory carefully, and verify installed versions before starting the server.

Best Practices

  • Commit one conservative baseline configuration and document every environment override.
  • Bind to 127.0.0.1 unless a remote client truly needs network access. Add network controls when binding to a broader interface.
  • Keep credentials out of config files, command history, screenshots, and uploaded logs.
  • Pin Appium and client libraries with the lockfile, and manage driver versions deliberately.
  • Use one base path consistently across server, client, proxy, and readiness checks.
  • Fail CI on readiness timeout and retain the server log for diagnosis.
  • Keep capabilities in client configuration unless a carefully reviewed shared default has a clear benefit.
  • Delete sessions in a finally block so a failed assertion does not leak server state.
  • Review config options during Appium upgrades by checking the installed version's help output.

Where To Go Next

Your server configuration is now repeatable, observable, and ready for a real suite. Continue with the complete Appium 3 mobile automation guide to place this server in a complete framework.

Then deepen the operational pieces:

Once those foundations are stable, add platform-specific test configuration, parallel worker port allocation, device inventory checks, and log artifact retention. Make each layer independently verifiable before scaling execution.

For broader framework work, use the WebdriverIO mobile testing guide to organize client-side configuration and the Android test automation guide to strengthen emulator, device, and application checks.

Interview Questions and Answers

Q: What belongs in an Appium 3 configuration file?

Server startup options such as address, port, base path, log level, and security-related settings belong in the file. Test capabilities usually belong in the client framework because they describe a requested session.

Q: How do you start Appium with a specific config file?

Run appium --config /path/to/appium.config.yaml, preferably through the project's local binary with npx or an npm script. An explicit path avoids differences caused by working directories or personal global setup.

Q: Why can the Appium status endpoint pass while session creation fails?

The status endpoint verifies that the server can receive requests. Session creation additionally depends on an installed compatible driver, a reachable device, valid capabilities, and a usable application.

Q: What causes a 404 after changing base-path?

The client or health check is probably calling a route without the configured prefix. Server base path, client path, proxy routing, and readiness URL must agree.

Q: How should a team handle local and CI differences?

Keep stable settings in a committed baseline file and use explicit CLI overrides or a reviewed CI-specific file for small differences. Supply secrets through the CI secret store, never through committed configuration.

Q: Why use a local Appium dependency instead of a global install?

A local dependency and lockfile make the server version visible and reproducible. An npm script also gives every contributor and CI job the same startup command.

Q: How do you verify an Appium config change safely?

Parse the file, start Appium from it, call the correct status URL, and create then delete a small real session. Each check isolates syntax, server routing, and driver integration failures.

Conclusion

A reliable Appium 3 configuration file is a small operational contract. Put server arguments under server, launch it explicitly with --config, keep capabilities in the client, and verify both readiness and a real session.

Commit the config with the lockfile, keep secrets outside the repository, and make the readiness check part of CI. That turns Appium startup from undocumented shell knowledge into a repeatable interface your whole automation team can trust.

Interview Questions and Answers

What is the purpose of an Appium 3 configuration file?

It makes Appium server startup repeatable by storing options such as address, port, base path, and logging. A committed file also makes changes reviewable and keeps local and CI behavior aligned. Session capabilities normally remain in the client.

How do you load a configuration file in Appium 3?

Start the server with appium --config followed by the file path. I prefer the project-local executable through npx or an npm script, and I use an explicit path in CI.

What is the difference between Appium server config and capabilities?

Server config controls the long-running Appium process, including its network and logging behavior. Capabilities are sent with a new-session request and specify the platform, driver, device, and application. Separating them keeps infrastructure settings independent from test intent.

How would you diagnose a base-path mismatch?

I compare the server base-path, client path, proxy route, and health-check URL. A server configured with /wd/hub should answer at /wd/hub/status, and the client should also use /wd/hub. A 404 with a running server is the key symptom.

How do you make Appium configuration safe for CI?

I commit nonsecret defaults, use a locked local Appium dependency, and pass limited environment overrides explicitly. I poll the status endpoint before tests, preserve diagnostic logs, and use the CI secret store for credentials.

Why is a successful status response not enough to validate an Appium setup?

It proves the HTTP server is ready, but it does not prove a driver can automate a device. I also create a small real session, perform one assertion such as reading page source, and delete the session.

How do you prevent configuration drift between developers?

I version the config, package manifest, and lockfile together, and expose one npm startup command. CI performs the same readiness and smoke checks, while machine-specific values use documented overrides instead of private edited copies.

Frequently Asked Questions

Where should I put the Appium 3 config file?

Put a team-owned config in the repository, commonly at the root or in a config directory. Start Appium with an explicit --config path so local and CI working-directory differences do not change which file is loaded.

Can Appium 3 use a YAML configuration file?

Yes. Put server options beneath a top-level server key and start Appium with appium --config followed by the YAML path. JSON and JavaScript configuration are alternatives when their tradeoffs fit your workflow.

Should desired capabilities go in the Appium config file?

Usually no. Capabilities describe a requested automation session, so keep them in the client test framework. The Appium config should primarily define how the server process starts and behaves.

How do I change the Appium base path to /wd/hub?

Set base-path to /wd/hub beneath server, then set the WebDriver client's path to /wd/hub too. Update the readiness endpoint to /wd/hub/status so all routing assumptions match.

How do I override the Appium config port in CI?

Pass --port with the CI-provided value after --config. Confirm the startup log and call the status endpoint on the overridden port before running tests.

Why does Appium say an option in my config is unknown?

The key may be in the wrong section, may include an incorrect prefix, or may not exist in your installed Appium version. Check npx appium --help and the installed version, then verify that server options are nested under server.

How can I verify an Appium config file before a full test suite?

Parse the YAML, start the server, poll the correctly prefixed status endpoint, and run one session smoke test. This sequence distinguishes file syntax, startup, routing, and driver failures.

Related Guides