Skip to main content

Overview

Skyvern generates various artifacts during workflow execution, including screenshots, downloaded files, HAR (HTTP Archive) files, and video recordings. By default, these are stored locally on the filesystem, but for production deployments, you should configure cloud storage for better scalability and durability.

Storage Types

Skyvern stores four types of data:
TypeDescriptionDefault PathTypical Size
ArtifactsScreenshots, downloaded files/data/artifactsVariable (1MB-100MB per task)
VideosBrowser session recordings/data/videos10-50MB per task
HAR FilesNetwork traffic logs/data/har1-10MB per task
LogsApplication logs/data/log1-5MB per day

Supported Storage Backends

Local Filesystem (Default)

Best for: Development, single-server deployments Configuration:
# .env
ARTIFACT_STORAGE_PATH=/data/artifacts
VIDEO_PATH=/data/videos
HAR_PATH=/data/har
LOG_PATH=/data/log
Docker Compose Volumes:
volumes:
  - ./artifacts:/data/artifacts
  - ./videos:/data/videos
  - ./har:/data/har
  - ./log:/data/log
Pros:
  • Simple setup, no additional services
  • Fast access
  • No egress costs
Cons:
  • Not suitable for multi-node deployments
  • No built-in redundancy
  • Manual backup required
  • Disk space management needed

AWS S3

Best for: Production deployments on AWS, multi-node Kubernetes clusters Configuration:
# .env
# S3 Artifact Storage
ARTIFACT_STORAGE_TYPE=s3
S3_BUCKET_NAME=skyvern-artifacts
S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key

# Optional: Custom S3 endpoint (for MinIO, etc.)
# S3_ENDPOINT_URL=https://s3.custom-domain.com

# Optional: Server-side encryption
# S3_SERVER_SIDE_ENCRYPTION=AES256
Setup Steps:
  1. Create S3 bucket:
aws s3 mb s3://skyvern-artifacts --region us-east-1
  1. Configure bucket lifecycle policy (optional, to auto-delete old artifacts):
{
  "Rules": [
    {
      "Id": "DeleteOldArtifacts",
      "Status": "Enabled",
      "Prefix": "artifacts/",
      "Expiration": {
        "Days": 90
      }
    },
    {
      "Id": "DeleteOldVideos",
      "Status": "Enabled",
      "Prefix": "videos/",
      "Expiration": {
        "Days": 30
      }
    }
  ]
}
  1. Set bucket policy for access:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SkyvernAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:user/skyvern-user"
      },
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::skyvern-artifacts/*",
        "arn:aws:s3:::skyvern-artifacts"
      ]
    }
  ]
}
  1. Create IAM user with S3 access:
aws iam create-user --user-name skyvern-storage
aws iam attach-user-policy --user-name skyvern-storage \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
aws iam create-access-key --user-name skyvern-storage
Docker Compose Example:
services:
  skyvern:
    environment:
      - ARTIFACT_STORAGE_TYPE=s3
      - S3_BUCKET_NAME=skyvern-artifacts
      - S3_REGION=us-east-1
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
Using IAM Roles (Recommended for EC2/EKS): Instead of access keys, use IAM instance roles:
services:
  skyvern:
    environment:
      - ARTIFACT_STORAGE_TYPE=s3
      - S3_BUCKET_NAME=skyvern-artifacts
      - S3_REGION=us-east-1
      # No access keys needed when using IAM role
Attach this policy to your EC2 instance or EKS service account:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::skyvern-artifacts/*",
        "arn:aws:s3:::skyvern-artifacts"
      ]
    }
  ]
}

Azure Blob Storage

Best for: Production deployments on Azure, Azure-integrated environments Configuration:
# .env
# Azure Blob Storage
ARTIFACT_STORAGE_TYPE=azure_blob
AZURE_STORAGE_ACCOUNT_NAME=skyvernartifacts
AZURE_STORAGE_CONTAINER_NAME=artifacts
AZURE_STORAGE_ACCOUNT_KEY=your-storage-account-key

# Alternative: Use Connection String
# AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
Setup Steps:
  1. Create Storage Account:
az storage account create \
  --name skyvernartifacts \
  --resource-group skyvern-rg \
  --location eastus \
  --sku Standard_LRS
  1. Create Container:
az storage container create \
  --name artifacts \
  --account-name skyvernartifacts
  1. Get Access Key:
az storage account keys list \
  --account-name skyvernartifacts \
  --resource-group skyvern-rg
  1. (Optional) Configure lifecycle management:
{
  "rules": [
    {
      "name": "deleteOldArtifacts",
      "enabled": true,
      "type": "Lifecycle",
      "definition": {
        "filters": {
          "blobTypes": ["blockBlob"],
          "prefixMatch": ["artifacts/"]
        },
        "actions": {
          "baseBlob": {
            "delete": {
              "daysAfterModificationGreaterThan": 90
            }
          }
        }
      }
    }
  ]
}
Docker Compose Example:
services:
  skyvern:
    environment:
      - ARTIFACT_STORAGE_TYPE=azure_blob
      - AZURE_STORAGE_ACCOUNT_NAME=skyvernartifacts
      - AZURE_STORAGE_CONTAINER_NAME=artifacts
      - AZURE_STORAGE_ACCOUNT_KEY=${AZURE_STORAGE_ACCOUNT_KEY}
Using Managed Identity (Recommended for Azure VMs/AKS):
services:
  skyvern:
    environment:
      - ARTIFACT_STORAGE_TYPE=azure_blob
      - AZURE_STORAGE_ACCOUNT_NAME=skyvernartifacts
      - AZURE_STORAGE_CONTAINER_NAME=artifacts
      - AZURE_CLIENT_ID=${AZURE_CLIENT_ID}  # Managed identity

MinIO (S3-Compatible)

Best for: On-premises deployments, self-hosted object storage Configuration:
# .env
ARTIFACT_STORAGE_TYPE=s3
S3_BUCKET_NAME=skyvern
S3_ENDPOINT_URL=http://minio:9000
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
S3_REGION=us-east-1  # Required but can be any value
Docker Compose with MinIO:
services:
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    ports:
      - 9000:9000
      - 9001:9001
    environment:
      - MINIO_ROOT_USER=minioadmin
      - MINIO_ROOT_PASSWORD=minioadmin
    volumes:
      - ./minio-data:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  skyvern:
    environment:
      - ARTIFACT_STORAGE_TYPE=s3
      - S3_BUCKET_NAME=skyvern
      - S3_ENDPOINT_URL=http://minio:9000
      - AWS_ACCESS_KEY_ID=minioadmin
      - AWS_SECRET_ACCESS_KEY=minioadmin
      - S3_REGION=us-east-1
    depends_on:
      - minio
Create bucket in MinIO:
# Using MinIO CLI (mc)
mc alias set local http://localhost:9000 minioadmin minioadmin
mc mb local/skyvern

Storage Path Structure

Skyvern organizes files with this structure:
<bucket or base path>/
├── artifacts/
│   ├── <task_id>/
│   │   ├── screenshot_001.png
│   │   ├── downloaded_file.pdf
│   │   └── element_<uuid>.png
│   └── <workflow_run_id>/
│       └── ...
├── videos/
│   ├── <task_id>.webm
│   └── <workflow_run_id>.webm
├── har/
│   ├── <task_id>.har
│   └── <workflow_run_id>.har
└── log/
    ├── skyvern_YYYY-MM-DD.log
    └── error_YYYY-MM-DD.log

Environment Variables Reference

General Storage Settings

# Storage backend type: "local", "s3", "azure_blob"
ARTIFACT_STORAGE_TYPE=local

# Local paths (used when ARTIFACT_STORAGE_TYPE=local)
ARTIFACT_STORAGE_PATH=/data/artifacts
VIDEO_PATH=/data/videos
HAR_PATH=/data/har
LOG_PATH=/data/log

S3 Storage Settings

ARTIFACT_STORAGE_TYPE=s3
S3_BUCKET_NAME=skyvern-artifacts
S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret

# Optional
S3_ENDPOINT_URL=https://s3.custom-domain.com
S3_SERVER_SIDE_ENCRYPTION=AES256
S3_USE_SSL=true

Azure Blob Storage Settings

ARTIFACT_STORAGE_TYPE=azure_blob
AZURE_STORAGE_ACCOUNT_NAME=skyvernartifacts
AZURE_STORAGE_CONTAINER_NAME=artifacts
AZURE_STORAGE_ACCOUNT_KEY=your-key

# Alternative: Connection String
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;...

# For Managed Identity
AZURE_CLIENT_ID=your-client-id

Testing Storage Configuration

After configuring storage, verify it works:
  1. Start Skyvern:
docker compose up -d
  1. Check logs for storage initialization:
docker compose logs skyvern | grep -i storage
Look for:
INFO: Initialized S3 storage backend
INFO: Connected to bucket: skyvern-artifacts
  1. Run a test task that generates artifacts:
from skyvern import Skyvern

skyvern = Skyvern()
task = await skyvern.run_task(
    prompt="Take a screenshot of google.com",
    url="https://google.com"
)
  1. Verify files are uploaded:
S3:
aws s3 ls s3://skyvern-artifacts/artifacts/
Azure Blob:
az storage blob list \
  --account-name skyvernartifacts \
  --container-name artifacts

Kubernetes Storage Configuration

Using S3 with Kubernetes

apiVersion: v1
kind: Secret
metadata:
  name: skyvern-backend-env
  namespace: skyvern
stringData:
  ARTIFACT_STORAGE_TYPE: s3
  S3_BUCKET_NAME: skyvern-artifacts
  S3_REGION: us-east-1
  AWS_ACCESS_KEY_ID: your-key
  AWS_SECRET_ACCESS_KEY: your-secret

Using Azure Blob with Kubernetes

apiVersion: v1
kind: Secret
metadata:
  name: skyvern-backend-env
  namespace: skyvern
stringData:
  ARTIFACT_STORAGE_TYPE: azure_blob
  AZURE_STORAGE_ACCOUNT_NAME: skyvernartifacts
  AZURE_STORAGE_CONTAINER_NAME: artifacts
  AZURE_STORAGE_ACCOUNT_KEY: your-key

Cost Optimization

S3 Storage Classes

Use lifecycle policies to move old artifacts to cheaper storage:
{
  "Rules": [
    {
      "Id": "TransitionToIA",
      "Status": "Enabled",
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER"
        }
      ],
      "Expiration": {
        "Days": 365
      }
    }
  ]
}

Azure Blob Access Tiers

# Set container default tier to Cool
az storage container create \
  --name artifacts \
  --account-name skyvernartifacts \
  --default-access-tier Cool

Compression

Enable compression for videos to reduce storage:
# .env
VIDEO_COMPRESSION=true
VIDEO_QUALITY=medium  # low, medium, high

Backup and Disaster Recovery

S3 Versioning

aws s3api put-bucket-versioning \
  --bucket skyvern-artifacts \
  --versioning-configuration Status=Enabled

S3 Cross-Region Replication

# Enable replication for disaster recovery
aws s3api put-bucket-replication \
  --bucket skyvern-artifacts \
  --replication-configuration file://replication.json

Azure Blob Soft Delete

az storage blob service-properties delete-policy update \
  --account-name skyvernartifacts \
  --enable true \
  --days-retained 7

Troubleshooting

”Access Denied” Errors

S3:
  • Verify IAM user has correct permissions
  • Check bucket policy
  • Ensure region matches
Azure:
  • Verify storage account key is correct
  • Check container exists
  • Verify network access (firewall rules)

Slow Upload Speeds

  • Use correct region (closest to deployment)
  • Enable multipart uploads for large files
  • Check network bandwidth

Storage Costs Too High

  • Implement lifecycle policies
  • Reduce video recording quality
  • Delete old artifacts programmatically
  • Use cheaper storage tiers

Next Steps

Environment Variables

Complete configuration reference

Docker Setup

Deploy with Docker Compose

Kubernetes Deployment

Production Kubernetes setup

Build docs developers (and LLMs) love