← BLOG

Playwright out of memory: stop Chromium from crashing

Reduce Playwright concurrency first. Reuse one browser, close every context in a finally block, limit open pages, and increase container memory only after the process has a bounded workload.

RUNNING APPS · 20 AUGUST 2026 · 6 MIN READ

When Playwright runs out of memory, first reduce how much browser work happens at once. Launch one browser, create an isolated context per job, close that context in a finally block, and cap parallel pages. More memory only postpones a leak or unbounded queue.

Chromium uses several processes, so Node's heap is only part of the total. A container can reach its memory limit even when process.memoryUsage() in the Node parent looks acceptable.

The error text points to different memory owners

WHAT YOU SEEWHAT IT SUGGESTSFIRST ACTION
Exit code 137 or SIGKILLThe container or operating system killed a process, often for memory pressureCompare total container use with its limit
JavaScript heap out of memoryThe Node process exhausted its V8 heapFind retained JavaScript objects and unbounded results
Target page, context or browser has been closedThe browser closed earlier, was killed, or your code closed itRead the lines before this secondary error
Browser process disappeared with no app exceptionChromium crashed outside the Node heapLower browser and page concurrency

Use one browser and disposable contexts

JS
import { chromium } from 'playwright';

const browser = await chromium.launch({ headless: true });

async function scrape(url) {
  const context = await browser.newContext();
  try {
    const page = await context.newPage();
    await page.goto(url, { waitUntil: 'domcontentloaded' });
    return await page.title();
  } finally {
    await context.close();
  }
}

try {
  for (const url of urls) await scrape(url);
} finally {
  await browser.close();
}
A bounded worker closes job state even when navigation or parsing fails.

A browser context gives each job isolated cookies and storage without paying for a new Chromium process. Playwright recommends closing created contexts before closing the browser so pages shut down cleanly.

Set a real concurrency budget

Replace an unbounded Promise.all with a queue that admits only a small number of pages. Start at one. Increase the limit while observing peak container memory and job duration. The correct number depends on the target pages, downloads, extensions, screenshots, and parsing work, so a universal value would be misleading.

  • Close pages and contexts after each job, including failure paths.
  • Do not retain page objects, responses, screenshots, or large HTML strings after their job finishes.
  • Block images, fonts, video, and analytics requests when the result does not need them.
  • Write completed output to durable storage instead of collecting an entire crawl in one array.
  • Apply backpressure when jobs arrive faster than the browser can finish them.
  • Use navigation and operation timeouts so a stuck page releases its slot.

Measure the parent, but remember the children

JS
const mb = (bytes) => Math.round(bytes / 1024 / 1024);
const m = process.memoryUsage();
console.log({ rssMB: mb(m.rss), heapUsedMB: mb(m.heapUsed) });
Useful for spotting growth in Node, not for measuring every Chromium child.

Log memory at the same points in each job: before creating a context, after closing it, and after a fixed number of jobs. A high but stable plateau means a larger plan may be justified. A line that keeps rising after every context closes needs investigation before scaling the container.

Docker has one Chromium-specific trap

When you control Docker, Playwright recommends running Chromium with host IPC because a small shared-memory area can make Chromium run out of memory and crash. That setting is a container-level choice. On a managed host where you cannot change Docker flags, reduce concurrency or choose a runtime designed for browser automation.

Choose the host after the workload is bounded

A request function fits a short screenshot or one isolated browser task. A continuous worker fits a monitor, queue consumer, or crawl loop. A browser service with many parallel sessions needs autoscaling and resource controls beyond a small single container.

Spocket's published runtime guidance places Playwright and Puppeteer on Builder or Fleet rather than Solo. It runs one continuous Node or Python process, restarts it after a crash, and keeps logs, but it does not add browser replicas. Use /run/scrapers for the hosting limits and /documentation/logs-and-status to inspect the lines before a killed process restarts.

Need somewhere to put it?

Spocket runs apps, workers and scrapers that have to stay awake. Deploy from Claude or Cursor by asking, from $3/mo. First app is free for 7 days, no card.

Scraper hostingRead the quickstart
Spocket
BlogDocsTermsPrivacyHome