
Selenium Grid Tutorial: Parallel Testing & Distributed Execution
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.
Table Of Contents-
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 Grid | With Grid |
|---|---|
| Tests run one at a time | Tests run in parallel |
| Limited to local browsers | Access to any browser/OS |
| Single machine bottleneck | Distributed across machines |
| 2-hour test suite | 15-minute test suite |
Grid Use Cases
- Faster feedback - Reduce CI/CD pipeline time
- Cross-browser coverage - Test all supported browsers
- Platform testing - Windows, macOS, Linux
- Scalability - Handle multiple concurrent users
- 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) │
└──────────┘ └──────────┘ └──────────┘| Component | Role |
|---|---|
| Router | Gateway that receives external requests and routes them to appropriate components |
| Distributor | Manages node registration, tracks capabilities, assigns sessions to nodes |
| Session Map | Stores mapping between Session IDs and Nodes |
| Session Queue | Holds incoming session requests in FIFO order |
| Event Bus | Enables internal communication between components |
| Node | Executes tests by running browser instances |
Component Interaction Flow
- Test sends new session request to Router
- Router forwards to Session Queue
- Distributor picks request, finds matching Node
- Node starts browser session
- Session Map stores Session ID → Node mapping
- Subsequent commands route directly to the Node
Setup Modes
Grid 4 supports three deployment modes:
| Mode | Components | Use Case |
|---|---|---|
| Standalone | All-in-one | Local development, small teams |
| Hub and Node | Hub + separate Nodes | Medium-scale, dedicated machines |
| Distributed | All components separate | Large-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 standaloneDefault 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.logViewing 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 hubThe hub listens on:
http://localhost:4444- Client connectionstcp://localhost:4442- Event publishingtcp://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:4444Node 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=2Multi-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=4Distributed 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=4pytest-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=4Running 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 downDynamic 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: 2Gshm_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 5558Vertical Scaling
Increase sessions per node:
java -jar selenium-server-4.21.0.jar node --max-sessions 8Resource guideline: Each browser session needs approximately:
- 1 CPU core
- 1 GB RAM
Cloud Grid Services
For large-scale testing, consider cloud Grid services:
| Service | Benefits |
|---|---|
| BrowserStack | No infrastructure management, 3000+ browser/OS combinations |
| Sauce Labs | Real devices, video recording, analytics |
| LambdaTest | Cost-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 1805. Monitor Grid Health
- Check Grid UI at
/uiregularly - 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?