UI Automation
Selenium WebDriver
Selenium Grid

Selenium Grid Tutorial: Parallel Testing & Distributed Execution

Parul Dhingra - Senior Quality Analyst
Parul Dhingra13+ Years ExperienceHire Me

Senior Quality Analyst

Updated: 1/23/2026

Running tests sequentially is slow and doesn't scale. A test suite that takes 2 hours to run locally can complete in 15 minutes when distributed across multiple browsers and machines. Selenium Grid makes this possible by routing WebDriver commands to remote browser instances, enabling parallel execution at scale.

Selenium Grid 4 is a complete rewrite designed for containerization, cloud scalability, and modern distributed architectures. This guide covers everything from basic setup to production-grade deployments.

What is Selenium Grid?

Selenium Grid enables running WebDriver tests on remote machines by routing commands sent by the client to remote browser instances. It's designed for:

  • Parallel execution - Run multiple tests simultaneously
  • Cross-browser testing - Test on Chrome, Firefox, Edge, Safari
  • Distributed testing - Spread tests across multiple machines
  • Environment variety - Test on different OS versions

Grid Benefits

Without GridWith Grid
Tests run one at a timeTests run in parallel
Limited to local browsersAccess to any browser/OS
Single machine bottleneckDistributed across machines
2-hour test suite15-minute test suite

Grid Use Cases

  1. Faster feedback - Reduce CI/CD pipeline time
  2. Cross-browser coverage - Test all supported browsers
  3. Platform testing - Windows, macOS, Linux
  4. Scalability - Handle multiple concurrent users
  5. Resource optimization - Centralize browser infrastructure

Grid 4 Architecture

Selenium Grid 4 introduced a completely redesigned architecture with six specialized components:

The Six Components

┌─────────────────────────────────────────────────────────────┐
│                         ROUTER                               │
│              (Entry point for all requests)                  │
└─────────────────────────┬───────────────────────────────────┘

         ┌────────────────┼────────────────┐
         ▼                ▼                ▼
┌─────────────┐   ┌─────────────┐   ┌─────────────┐
│ DISTRIBUTOR │   │ SESSION MAP │   │SESSION QUEUE│
│(Assigns     │   │(Session ID  │   │(Holds new   │
│ sessions)   │   │ to Node)    │   │ requests)   │
└─────────────┘   └─────────────┘   └─────────────┘
         │                                 │
         │         ┌───────────┐           │
         └────────►│ EVENT BUS │◄──────────┘
                   │(Internal  │
                   │ messaging)│
                   └─────┬─────┘

         ┌───────────────┼───────────────┐
         ▼               ▼               ▼
   ┌──────────┐    ┌──────────┐    ┌──────────┐
   │  NODE 1  │    │  NODE 2  │    │  NODE 3  │
   │ (Chrome) │    │ (Firefox)│    │  (Edge)  │
   └──────────┘    └──────────┘    └──────────┘
ComponentRole
RouterGateway that receives external requests and routes them to appropriate components
DistributorManages node registration, tracks capabilities, assigns sessions to nodes
Session MapStores mapping between Session IDs and Nodes
Session QueueHolds incoming session requests in FIFO order
Event BusEnables internal communication between components
NodeExecutes tests by running browser instances

Component Interaction Flow

  1. Test sends new session request to Router
  2. Router forwards to Session Queue
  3. Distributor picks request, finds matching Node
  4. Node starts browser session
  5. Session Map stores Session ID → Node mapping
  6. Subsequent commands route directly to the Node

Setup Modes

Grid 4 supports three deployment modes:

ModeComponentsUse Case
StandaloneAll-in-oneLocal development, small teams
Hub and NodeHub + separate NodesMedium-scale, dedicated machines
DistributedAll components separateLarge-scale, cloud deployment

Standalone Mode

Standalone combines all components into a single process. It's the simplest way to run Grid.

Starting Standalone Grid

# Download Selenium Server
wget https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.21.0/selenium-server-4.21.0.jar
 
# Start standalone grid
java -jar selenium-server-4.21.0.jar standalone

Default URL: http://localhost:4444

Standalone Configuration

# Custom port
java -jar selenium-server-4.21.0.jar standalone --port 5555
 
# Specific browsers
java -jar selenium-server-4.21.0.jar standalone \
  --detect-drivers false \
  --driver-configuration display-name="Chrome" max-sessions=4
 
# Enable logging
java -jar selenium-server-4.21.0.jar standalone --log selenium-grid.log

Viewing Grid Status

Open http://localhost:4444/ui in a browser to see:

  • Active sessions
  • Available nodes
  • Queue status
  • Session history

Standalone Limitations: Runs on a single machine with limited scalability. Use Hub-Node or Distributed mode for production environments.

Hub and Node Mode

Hub-Node mode separates the hub (coordinator) from nodes (executors), allowing nodes on different machines.

Starting the Hub

java -jar selenium-server-4.21.0.jar hub

The hub listens on:

  • http://localhost:4444 - Client connections
  • tcp://localhost:4442 - Event publishing
  • tcp://localhost:4443 - Event subscribing

Starting Nodes

# Same machine as hub
java -jar selenium-server-4.21.0.jar node
 
# Different machine (specify hub address)
java -jar selenium-server-4.21.0.jar node \
  --hub http://hub-machine:4444

Node Configuration Options

# Limit sessions per browser
java -jar selenium-server-4.21.0.jar node \
  --max-sessions 5 \
  --session-timeout 300
 
# Specify browser drivers
java -jar selenium-server-4.21.0.jar node \
  --driver-configuration display-name="Chrome" stereotype='{"browserName":"chrome"}' max-sessions=3 \
  --driver-configuration display-name="Firefox" stereotype='{"browserName":"firefox"}' max-sessions=2

Multi-Node Setup Example

# Terminal 1: Start Hub
java -jar selenium-server-4.21.0.jar hub
 
# Terminal 2: Chrome Node
java -jar selenium-server-4.21.0.jar node \
  --port 5555 \
  --driver-configuration display-name="Chrome" stereotype='{"browserName":"chrome"}' max-sessions=4
 
# Terminal 3: Firefox Node
java -jar selenium-server-4.21.0.jar node \
  --port 5556 \
  --driver-configuration display-name="Firefox" stereotype='{"browserName":"firefox"}' max-sessions=4

Distributed Mode

Distributed mode runs each component as a separate process, providing maximum scalability and resilience.

Starting Each Component

# 1. Event Bus
java -jar selenium-server-4.21.0.jar event-bus
 
# 2. Session Map
java -jar selenium-server-4.21.0.jar sessions
 
# 3. Session Queue
java -jar selenium-server-4.21.0.jar sessionqueue
 
# 4. Distributor
java -jar selenium-server-4.21.0.jar distributor \
  --sessions http://localhost:5556 \
  --sessionqueue http://localhost:5559 \
  --bind-bus false
 
# 5. Router
java -jar selenium-server-4.21.0.jar router \
  --sessions http://localhost:5556 \
  --distributor http://localhost:5553 \
  --sessionqueue http://localhost:5559
 
# 6. Nodes
java -jar selenium-server-4.21.0.jar node
⚠️

Distributed Mode Complexity: Only use distributed mode when you need to scale individual components independently or require high availability. Hub-Node mode is sufficient for most use cases.

Connecting Tests to Grid

Tests connect to Grid using RemoteWebDriver instead of local browser drivers.

Java Example

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.net.URL;
 
public class GridTest {
    public static void main(String[] args) throws Exception {
        // Configure browser capabilities
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless");
 
        // Connect to Grid
        URL gridUrl = new URL("http://localhost:4444");
        WebDriver driver = new RemoteWebDriver(gridUrl, options);
 
        try {
            driver.get("https://example.com");
            System.out.println("Title: " + driver.getTitle());
        } finally {
            driver.quit();
        }
    }
}

Python Example

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
 
# Configure browser
options = Options()
options.add_argument("--headless")
 
# Connect to Grid
driver = webdriver.Remote(
    command_executor='http://localhost:4444',
    options=options
)
 
try:
    driver.get("https://example.com")
    print(f"Title: {driver.title}")
finally:
    driver.quit()

Specifying Browser and Platform

// Request specific browser
ChromeOptions chrome = new ChromeOptions();
chrome.setCapability("browserName", "chrome");
chrome.setCapability("platformName", "linux");
 
// Request Firefox
FirefoxOptions firefox = new FirefoxOptions();
firefox.setCapability("browserName", "firefox");
 
// Request Edge
EdgeOptions edge = new EdgeOptions();
edge.setCapability("browserName", "MicrosoftEdge");

Parallel Test Execution

Grid's real power comes from running tests in parallel. Use test frameworks to distribute tests across Grid.

TestNG Parallel Configuration

<!-- testng.xml -->
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parallel Suite" parallel="methods" thread-count="5">
    <test name="Chrome Tests">
        <parameter name="browser" value="chrome"/>
        <classes>
            <class name="tests.LoginTest"/>
            <class name="tests.SearchTest"/>
        </classes>
    </test>
</suite>

Thread-Safe Test Design

public class BaseTest {
    // ThreadLocal ensures each thread gets its own driver instance
    private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
 
    @BeforeMethod
    @Parameters("browser")
    public void setup(String browser) throws MalformedURLException {
        WebDriverOptions options = getBrowserOptions(browser);
        driver.set(new RemoteWebDriver(
            new URL("http://localhost:4444"),
            options
        ));
    }
 
    @AfterMethod
    public void teardown() {
        if (driver.get() != null) {
            driver.get().quit();
            driver.remove();
        }
    }
 
    protected WebDriver getDriver() {
        return driver.get();
    }
}

JUnit 5 Parallel Execution

# junit-platform.properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=4

pytest-xdist for Python

# Install parallel plugin
pip install pytest-xdist
 
# Run with 4 parallel workers
pytest -n 4 tests/
# conftest.py
import pytest
from selenium import webdriver
 
@pytest.fixture
def driver():
    driver = webdriver.Remote(
        command_executor='http://localhost:4444',
        options=webdriver.ChromeOptions()
    )
    yield driver
    driver.quit()

Docker Deployment

Docker is the recommended way to run Selenium Grid in production.

Docker Compose Setup

# docker-compose.yml
version: "3"
services:
  selenium-hub:
    image: selenium/hub:4.21.0
    container_name: selenium-hub
    ports:
      - "4442:4442"
      - "4443:4443"
      - "4444:4444"
 
  chrome:
    image: selenium/node-chrome:4.21.0
    shm_size: 2gb
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=4
 
  firefox:
    image: selenium/node-firefox:4.21.0
    shm_size: 2gb
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=4
 
  edge:
    image: selenium/node-edge:4.21.0
    shm_size: 2gb
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=4

Running Docker Grid

# Start Grid
docker-compose up -d
 
# Scale Chrome nodes
docker-compose up -d --scale chrome=3
 
# View logs
docker-compose logs -f
 
# Stop Grid
docker-compose down

Dynamic Grid (Auto-scaling)

# docker-compose-dynamic.yml
version: "3"
services:
  selenium-hub:
    image: selenium/hub:4.21.0
    ports:
      - "4444:4444"
    environment:
      - SE_NODE_MAX_SESSIONS=4
      - SE_NODE_SESSION_TIMEOUT=300
 
  chrome:
    image: selenium/node-chrome:4.21.0
    shm_size: 2gb
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
    deploy:
      replicas: 2
      resources:
        limits:
          memory: 2G

shm_size Important: Set shm_size: 2gb for browser containers. Chrome and Firefox use /dev/shm for shared memory, and the default 64MB causes crashes.

Scaling Strategies

Horizontal Scaling

Add more nodes to increase capacity:

# Add more Chrome nodes
docker-compose up -d --scale chrome=5
 
# Or start additional node processes
java -jar selenium-server-4.21.0.jar node --port 5557
java -jar selenium-server-4.21.0.jar node --port 5558

Vertical Scaling

Increase sessions per node:

java -jar selenium-server-4.21.0.jar node --max-sessions 8

Resource guideline: Each browser session needs approximately:

  • 1 CPU core
  • 1 GB RAM

Cloud Grid Services

For large-scale testing, consider cloud Grid services:

ServiceBenefits
BrowserStackNo infrastructure management, 3000+ browser/OS combinations
Sauce LabsReal devices, video recording, analytics
LambdaTestCost-effective, good parallel capacity
// Example: BrowserStack connection
MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("browserName", "Chrome");
capabilities.setCapability("browserVersion", "latest");
 
HashMap<String, Object> bstackOptions = new HashMap<>();
bstackOptions.put("os", "Windows");
bstackOptions.put("osVersion", "11");
bstackOptions.put("userName", "YOUR_USERNAME");
bstackOptions.put("accessKey", "YOUR_ACCESS_KEY");
capabilities.setCapability("bstack:options", bstackOptions);
 
WebDriver driver = new RemoteWebDriver(
    new URL("https://hub-cloud.browserstack.com/wd/hub"),
    capabilities
);

Best Practices

1. Use ThreadLocal for Parallel Tests

// Each thread gets its own driver instance
private static ThreadLocal<WebDriver> driverThread = new ThreadLocal<>();
 
public static WebDriver getDriver() {
    return driverThread.get();
}

2. Make Tests Stateless

// Bad: Tests depend on shared state
static User loggedInUser; // Causes race conditions
 
// Good: Each test creates its own data
@Test
public void testUserProfile() {
    User user = createTestUser(); // Fresh data per test
    loginAs(user);
    // ...
}

3. Clean Up Sessions

@AfterMethod(alwaysRun = true)
public void cleanup() {
    if (getDriver() != null) {
        getDriver().quit();
    }
}

4. Set Appropriate Timeouts

# Grid configuration
java -jar selenium-server-4.21.0.jar standalone \
  --session-timeout 300 \
  --session-request-timeout 180

5. Monitor Grid Health

  • Check Grid UI at /ui regularly
  • Monitor queue length
  • Watch for stuck sessions
  • Set up alerts for node failures

6. Use Explicit Waits

Grid adds network latency. Avoid flaky tests:

// Always use explicit waits with RemoteWebDriver
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));

Test Your Knowledge

Quiz on Selenium Grid

Your Score: 0/10

Question: What is the primary benefit of using Selenium Grid?


Continue Your Selenium Journey


Frequently Asked Questions

Frequently Asked Questions (FAQs) / People Also Ask (PAA)

What's the difference between Selenium Grid 3 and Grid 4?

Should I use Selenium Grid or a cloud service like BrowserStack?

How many parallel sessions can Selenium Grid handle?

Why do my Grid tests fail with timeout errors?

How do I run tests on specific browsers or operating systems?

Can I run Selenium Grid in Kubernetes?

How do I debug tests running on Selenium Grid?

What is the Session Queue timeout and how do I configure it?