# Lightpanda Fetch Mode vs Serve Mode: Understanding the Difference

> Understand Lightpanda fetch mode vs serve mode. Fetch performs single page retrieval, while serve launches a persistent CDP server for interactive browser automation.

- Repository: [Lightpanda/browser](https://github.com/lightpanda-io/browser)
- Tags: deep-dive
- Published: 2026-03-14

---

**Fetch mode performs a single-shot page retrieval with optional content dumping to stdout or file, while serve mode launches a persistent Chrome DevTools Protocol (CDP) server that accepts remote WebSocket connections for interactive browser automation.**

Lightpanda is a lightweight, headless browser written in Zig designed for high-performance web automation. The `src/Config.zig` file defines distinct **run modes** that determine how the browser initializes and executes, with `fetch` and `serve` representing two fundamentally different architectural approaches. Understanding these modes ensures you select the appropriate method for one-off data extraction versus long-running automation workflows.

## Configuration Architecture

The behavioral differences between fetch and serve mode originate in their respective configuration structures within `src/Config.zig`.

### Fetch Mode Configuration

**`Config.Fetch`** (defined at lines 220–227) contains the target URL, dump format options (HTML, markdown, semantic tree), and a shared `Common` configuration block. This structure supports the single-execution pattern where the process terminates immediately after retrieving and optionally serializing the document.

### Serve Mode Configuration

**`Config.Serve`** (defined at lines 199–206) specifies network parameters including host, port, timeout settings, and connection limits alongside the `Common` block. Unlike fetch mode, this configuration supports persistent socket listening and multi-session management required for remote protocol support.

## Operational Implementation

The entry points in `src/main.zig` (around lines 84–105) dispatch to entirely different execution paths based on the selected mode.

### Fetch Mode: Single-Shot Execution

When invoked with `case .fetch`, the application constructs a `FetchOpts` structure and calls `lp.fetch(app, url, fetch_opts)`. The core implementation in `src/lightpanda.zig` (lines 52–63 and 104–136) performs the following sequence:

1. Instantiates a `Browser` object
2. Navigates to the specified URL
3. Waits for page stabilization
4. Serializes the document or semantic tree if dump mode is enabled
5. Writes output to the configured writer (stdout or file)
6. Terminates the process

This mode is ideal for static-site generation, one-off page extraction, or pipeline debugging where no ongoing interaction is required.

### Serve Mode: Persistent CDP Server

When invoked with `case .serve`, the `main.zig` branch (lines 84–102) initializes a `lp.Server` instance that implements the Chrome DevTools Protocol. The implementation in `src/Server.zig` establishes a listening socket and enters a network loop that:

- Accepts incoming WebSocket connections
- Dispatches CDP messages to underlying `Browser` sessions
- Maintains process longevity until interrupted (SIGTERM, Ctrl-C)

This architecture enables external tools like Puppeteer, Playwright, or chromedp to connect via `ws://host:port` and control multiple pages programmatically across extended sessions.

## Practical Usage Examples

### Running Fetch Mode

Execute a one-time page capture with content dumping:

```bash

# Dump rendered HTML to file

./lightpanda fetch --dump html https://example.com > page.html

# Extract markdown representation

./lightpanda fetch --dump markdown https://example.com > page.md

# Output JSON-encoded semantic tree to stdout

./lightpanda fetch --dump semantic_tree https://example.com

```

### Running Serve Mode

Start the CDP server for remote automation:

```bash

# Default binding (127.0.0.1:9222)

./lightpanda serve

# Custom network interface and port

./lightpanda serve --host 0.0.0.0 --port 8080

```

Connect programmatically using Puppeteer:

```javascript
const puppeteer = require('puppeteer-core');
const browser = await puppeteer.connect({
  browserWSEndpoint: 'ws://127.0.0.1:9222',
});
const page = await browser.newPage();
await page.goto('https://example.com');

```

## Summary

- **Fetch mode** uses `Config.Fetch` to execute a single navigation, dump content via `lp.fetch()` in `src/lightpanda.zig`, and exit immediately.
- **Serve mode** uses `Config.Serve` to instantiate a persistent CDP server via `src/Server.zig`, maintaining WebSocket connections for remote automation.
- Fetch mode directs output to files or stdout, while serve mode communicates exclusively through CDP protocol messages.
- Fetch mode terminates after page retrieval; serve mode runs indefinitely until signal interruption.

## Frequently Asked Questions

### When should I use fetch mode instead of serve mode?

Use **fetch mode** for batch processing, static-site generation, or CI/CD pipelines where you need to extract content from specific URLs without maintaining a persistent browser instance. Use **serve mode** when integrating with existing automation frameworks like Puppeteer or Playwright that require interactive session management across multiple page navigations.

### Can fetch mode handle JavaScript-heavy applications?

Yes, the `lp.fetch()` implementation in `src/lightpanda.zig` instantiates a full `Browser` instance and waits for page stabilization before dumping, ensuring JavaScript execution completes. However, unlike serve mode, you cannot interact with the page after initial load or perform multi-step workflows.

### What network protocols does serve mode support?

**Serve mode** implements the **Chrome DevTools Protocol (CDP)** over WebSocket connections, as defined in `src/Server.zig`. This allows compatibility with any tool supporting CDP, including Puppeteer, Playwright, and Selenium ChromeDriver, without requiring proprietary extensions.

### How do I limit concurrent connections in serve mode?

The `Config.Serve` structure in `src/Config.zig` (lines 199–206) includes connection limit parameters that control the maximum number of simultaneous WebSocket sessions. Configure these via command-line flags when starting the server to prevent resource exhaustion during high-concurrency automation scenarios.