Skip to main content
Puppeteer is a Node.js library that provides a high-level API for controlling headless Chrome and Chromium browsers. It enables developers to automate browser tasks such as generating PDFs, taking screenshots, scraping websites, running end-to-end tests, and simulating user interactions. With its powerful DevTools integration, Puppeteer offers precise control over page behavior, network requests, and rendering, making it a popular choice for automation, testing, and web content processing. Puppeteer can only be used on Application Hosting; it cannot be deployed as a static site.

Configuration

We recommend the following best practices when using Puppeteer with Sevalla:
  • Always make sure your processes terminate cleanly by calling process.exit(0)
  • Implement robust error handling and logging to prevent unwanted crashes.
  • Use an external job queue (e.g., Redis, BullMQ) for reliable background processing.
  • Add detailed logging to help troubleshoot Puppeteer and browser-related issues.
  • Always close browser and page instances to avoid memory leaks and runaway processes.
  • Run Puppeteer with the --no-sandbox and --disable-setuid-sandbox flags in production.
  • Test all Puppeteer scripts locally before deploying to Sevalla.
When deploying with a Dockerfile, make sure all required Chrome/Chromium system dependencies are installed. For generated output, such as PDFs or screenshots, use Sevalla’s object storage or integrate an external storage service like S3.

Containerization

Dockerfile

The build for Dockerfiles is fully customizable. We recommend using a multi-stage build approach with three stages:
  1. deps - Install Chromium and Node.js dependencies.
  2. builder - Build TypeScript code.
  3. runner - Final production image with minimal size.
Example Dockerfile:
# Stage 1: Dependencies
FROM node:lts-alpine AS deps
WORKDIR /app

# Install Chromium and system dependencies
RUN apk add --no-cache \
    chromium \
    nss \
    freetype \
    harfbuzz \
    ca-certificates \
    ttf-freefont

# Configure Puppeteer to use system Chromium
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

COPY package*.json ./
RUN npm ci

# Stage 2: Builder
FROM node:lts-alpine AS builder
WORKDIR /app

RUN apk add --no-cache \
    chromium \
    nss \
    freetype \
    harfbuzz \
    ca-certificates \
    ttf-freefont

ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN npm run build

# Stage 3: Runner (Production)
FROM node:lts-alpine AS runner
WORKDIR /app

# Install Chromium and dependencies
RUN apk add --no-cache \
    chromium \
    nss \
    freetype \
    harfbuzz \
    ca-certificates \
    ttf-freefont \
    && rm -rf /var/cache/apk/*

ENV NODE_ENV=production
ENV PORT=3000
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

# Create non-root user for security
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 puppeteeruser

COPY --from=builder --chown=puppeteeruser:nodejs /app/dist ./dist
COPY --from=builder --chown=puppeteeruser:nodejs /app/package*.json ./
COPY --from=builder --chown=puppeteeruser:nodejs /app/node_modules ./node_modules

USER puppeteeruser

EXPOSE 3000

CMD ["node", "dist/server.js"]
This Dockerfile includes the following key features:
  1. Alpine Linux Base
    • Uses node:lts-alpine for minimal image size
    • Includes only essential Chromium dependencies
    • Results in smaller, faster deployments
  2. System Chromium
    • Installs Chromium via apk package manager
    • Avoids duplicate browser downloads
    • More reliable than Puppeteer’s bundled Chromium
    • Environment variables configure Puppeteer to use system Chromium:
      PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
      PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
      
  3. Security
    • Runs as non-root user (puppeteeruser)
    • Follows the least-privilege principle
    • Safer for production deployments
  4. Multi-stage Build
    1. Separates build dependencies from runtime
    2. Reduces final image size
    3. Only production dependencies in the final image

Nixpacks

Nixpacks automatically detects your project type and creates an optimized build plan. You can customize the Nixpacks build process by defining a nixpacks.toml file. This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied. The following is an example nixpacks.toml configuration:
[phases.setup]
nixPkgs = ["nodejs_lts", "chromium"]

[phases.install]
cmds = [
  "npm ci"
]

[phases.build]
cmds = [
  "npm run build",
  "npx puppeteer browsers install chrome"
]

[start]
cmd = "node dist/server.js"

Build phases

1. Setup phase
[phases.setup]
nixPkgs = ["nodejs_lts", "chromium"]
  • nodejs_lts: Installs the latest Node.js.
  • chromium: Installs system-level Chromium browser and all necessary dependencies. This ensures Chrome/Chromium is available for Puppeteer without manual Dockerfile configuration.
2. Install phase
[phases.install]
cmds = ["npm ci"]
  • npm ci: Performs a clean install using package-lock.json. This ensures deterministic, reproducible builds, and it is faster and more reliable than npm install for production.
3. Build phase
[phases.build]
cmds = [
  "npm run build",
  "npx puppeteer browsers install chrome"
]
  • npm run build: Compiles TypeScript to JavaScript (outputs to dist/ directory).
  • npx puppeteer browsers install chrome: Downloads Chrome browser for Puppeteer.
  • Both commands run sequentially during deployment.
4. Start command
[start]
cmd = "node dist/server.js"
  • Starts the application by running the compiled JavaScript.
  • Points to dist/server.js (adjust this if your entry point is different, e.g., dist/index.js).