Skip to main content
This guide walks you through deploying Skyvern using Docker Compose. By the end, you’ll have a working Skyvern instance with the API server, browser, database, and web UI running on your machine.

Prerequisites

  • Docker and Docker Compose v2 installed (Get Docker). All commands use docker compose (with a space). If you have an older installation, replace with docker-compose.
  • 4GB+ RAM available
  • An LLM API key (OpenAI, Anthropic, Azure, Gemini, or Bedrock)

Quick start

1. Clone the repository

git clone https://github.com/Skyvern-AI/skyvern.git
cd skyvern

2. Configure environment variables

Copy the example environment file and configure your LLM provider:
cp .env.example .env
Open .env and set your LLM provider. Here’s an example for OpenAI:
.env
ENABLE_OPENAI=true
OPENAI_API_KEY=sk-your-api-key-here
LLM_KEY=OPENAI_GPT4O
For other providers, see LLM Configuration.

3. Configure the frontend

Copy the frontend environment file:
cp skyvern-frontend/.env.example skyvern-frontend/.env
The default values work for local development. You’ll update VITE_SKYVERN_API_KEY after the first startup.

4. Start the services

docker compose up -d
This pulls the images and starts three services:
  • postgres: Database on port 5432 (internal only)
  • skyvern: API server on port 8000
  • skyvern-ui: Web interface on port 8080
First startup takes 1-2 minutes as it runs database migrations and creates your organization.

5. Get your API key

Wait for all services to be healthy before continuing:
docker compose ps
All three services should show healthy in the STATUS column. The skyvern container runs database migrations and generates credentials on first startup. This takes 1-2 minutes. Once healthy, retrieve your API key:
cat .streamlit/secrets.toml
This file is auto-generated by Skyvern on first startup. The .streamlit path is a legacy artifact. The credentials inside are standard Skyvern API keys. You’ll see output like:
[skyvern]
configs = [
    {env = "local", host = "http://skyvern:8000/api/v1", orgs = [{name="Skyvern", cred="eyJhbGciOiJIUzI1..."}]}
]
The host value uses the Docker-internal hostname skyvern. From your machine, use http://localhost:8000 instead. You only need the cred value. This is your API key.

6. Update frontend configuration

Add your API key to the frontend environment:
skyvern-frontend/.env
VITE_SKYVERN_API_KEY=eyJhbGciOiJIUzI1...
Restart the UI to pick up the change:
docker compose restart skyvern-ui

7. Verify the installation

Open http://localhost:8080 in your browser. You should see the Skyvern dashboard. Test the API by listing workflows (should return an empty array on fresh install):
curl -s http://localhost:8000/v1/workflows \
  -H "x-api-key: YOUR_API_KEY_HERE"
The API accepts requests on both /v1/ and /api/v1/. The frontend uses /api/v1 for backward compatibility. New integrations should use /v1/.

Understanding the services

The Docker Compose file defines three services that work together:
ServiceImagePortsPurpose
postgrespostgres:14-alpine5432 (internal)Stores tasks, workflows, credentials, and run history
skyvernpublic.ecr.aws/skyvern/skyvern8000, 9222API server + embedded browser
skyvern-uipublic.ecr.aws/skyvern/skyvern-ui8080, 9090Web dashboard and artifact server
The skyvern container includes Playwright with Chromium. The browser runs inside the same container as the API server. No separate browser service is needed.

Data volumes

Docker Compose mounts several directories for persistent storage:
Local pathContainer pathContents
./postgres-data/var/lib/postgresql/dataDatabase files
./artifacts/data/artifactsExtracted data, screenshots
./videos/data/videosBrowser session recordings
./har/data/harHTTP Archive files for debugging
./log/data/logApplication logs
./.streamlit/app/.streamlitGenerated API credentials

Environment variables reference

The .env file controls the Skyvern server. Here are the most important variables grouped by purpose.

LLM Configuration

Configure at least one LLM provider. See LLM Configuration for all providers.
# OpenAI
ENABLE_OPENAI=true
OPENAI_API_KEY=sk-...
LLM_KEY=OPENAI_GPT4O

# Or Anthropic
ENABLE_ANTHROPIC=true
ANTHROPIC_API_KEY=sk-ant-...
LLM_KEY=ANTHROPIC_CLAUDE3.5_SONNET

Browser settings

# Browser mode: chromium-headful (visible) or chromium-headless (no display)
BROWSER_TYPE=chromium-headful

# Timeout for individual browser actions (milliseconds)
BROWSER_ACTION_TIMEOUT_MS=5000

# Where to save recordings
VIDEO_PATH=./videos

Task execution

# Maximum steps before a task times out
MAX_STEPS_PER_RUN=10

# Server port
PORT=8000

# Log verbosity: DEBUG, INFO, WARNING, ERROR
LOG_LEVEL=INFO

Database

The database connection is set in docker-compose.yml, not .env:
environment:
  - DATABASE_STRING=postgresql+psycopg://skyvern:skyvern@postgres:5432/skyvern
To use an external database, update this connection string and remove the postgres service.

Common operations

View logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f skyvern

Restart after configuration changes

docker compose restart skyvern

Stop all services

docker compose down

Update to latest version

docker compose pull
docker compose up -d

Reset everything (including database)

This deletes all data including task history, credentials, and recordings.
docker compose down -v
rm -rf postgres-data artifacts videos har log .streamlit
docker compose up -d

Exposing to the network

By default, Skyvern only accepts connections from localhost. To expose it on your network:

Option 1: Bind to all interfaces

Edit docker-compose.yml to change the port bindings:
services:
  skyvern:
    ports:
      - "0.0.0.0:8000:8000"  # Accept connections from any IP

Option 2: Use a reverse proxy

For production deployments, put Skyvern behind nginx or Traefik:
your-domain.com → nginx → localhost:8080 (UI)
api.your-domain.com → nginx → localhost:8000 (API)
Update the frontend environment to use your domain:
skyvern-frontend/.env
VITE_API_BASE_URL=https://api.your-domain.com/api/v1
VITE_WSS_BASE_URL=wss://api.your-domain.com/api/v1
VITE_ARTIFACT_API_BASE_URL=https://artifacts.your-domain.com
If exposing Skyvern to the internet, add authentication at the reverse proxy layer or use a VPN.

Troubleshooting

Check the logs for the failing service:
docker compose logs skyvern
Common causes:
  • Missing or invalid LLM API key: look for LLM-related errors in logs
  • Database connection failed: check if postgres service is healthy with docker compose ps
The API key is missing, malformed, or doesn’t match the organization. Verify:
  1. The x-api-key header is included in your request
  2. The key matches exactly what’s in .streamlit/secrets.toml
  3. No extra whitespace or newlines in the key
# Correct format
curl -H "x-api-key: eyJhbGciOiJIUzI1..." http://localhost:8000/v1/workflows
The API key format is invalid (JWT decode failed). This usually means:
  • The key was truncated or corrupted during copy-paste
  • You’re using an API key from a different Skyvern installation
Regenerate credentials by resetting the installation:
rm -rf .streamlit
docker compose restart skyvern
cat .streamlit/secrets.toml  # Get new key
Check that skyvern-frontend/.env has the correct values:
VITE_API_BASE_URL=http://localhost:8000/api/v1
VITE_WSS_BASE_URL=ws://localhost:8000/api/v1
VITE_SKYVERN_API_KEY=<your-key-from-secrets.toml>
After updating, restart the UI:
docker compose restart skyvern-ui
The BROWSER_TYPE environment variable has an invalid value. Valid options:
  • chromium-headful: Browser with visible window (default)
  • chromium-headless: No visible window
  • cdp-connect: Connect to external Chrome
The page content is too large for the LLM. Try:
  • Simplifying your prompt
  • Starting from a more specific URL
  • Using a model with a larger context window

Next steps

LLM Configuration

Configure OpenAI, Anthropic, Azure, Ollama, and other providers

Browser Configuration

Customize browser settings, locales, and connect to external Chrome

Storage Configuration

Store artifacts in S3 or Azure Blob instead of local disk

Proxy Setup

Configure proxies to avoid bot detection