Skip to main content

How to Self-Host Activepieces: Open Source Zapier Alternative 2026

·OSSAlt Team
activepiecesautomationzapierself-hostingdockerworkflows2026

TL;DR

Activepieces (MIT, ~10K GitHub stars, TypeScript) is a fully open source Zapier alternative — no usage limits, no locked features, 100% MIT licensed. Zapier charges $29.99/month for 750 tasks. Activepieces self-hosted gives you unlimited flows, unlimited runs, and all 100+ integrations free. The visual flow builder is clean, each step is a "piece" (Activepieces terminology for integration), and you can write custom TypeScript pieces to add any integration.

Key Takeaways

  • Activepieces: MIT, ~10K stars, TypeScript — 100% open source, no feature gating
  • 100+ pieces: Slack, Gmail, GitHub, Notion, PostgreSQL, HTTP requests, and more
  • Unlimited flows: No task limits on self-hosted — limited only by your hardware
  • Custom pieces: Write TypeScript to add any integration not in the catalog
  • Simple Docker: Single docker compose up -d to get started
  • vs n8n: Activepieces is simpler/cleaner UI; n8n has more integrations and code flexibility

Activepieces vs n8n vs Zapier

FeatureActivepiecesn8nZapier
LicenseMITSustainable UseProprietary
GitHub Stars~10K~51K
Cost (self-hosted)FreeFree$299/mo
Integrations100+400+6000+
Code nodesTypeScriptJS + PythonLimited
Visual builderExcellentGoodExcellent
AI/LLM nodesYes (basic)Yes (LangChain)Limited
Custom integrationsTypeScript piecesCustom nodesNo
Learning curveLowMediumLow
Best forSimple automationsComplex workflowsHosted simplicity

Part 1: Docker Setup

# docker-compose.yml
services:
  activepieces:
    image: activepieces/activepieces:latest
    container_name: activepieces
    restart: unless-stopped
    ports:
      - "8080:80"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      AP_ENGINE_EXECUTABLE_PATH: dist/packages/engine/main.js
      AP_ENVIRONMENT: prod
      AP_FRONTEND_URL: "https://flows.yourdomain.com"
      AP_WEBHOOK_TIMEOUT_SECONDS: 30
      AP_MAX_FILE_SIZE_MB: 10
      AP_TELEMETRY_ENABLED: "false"
      AP_SIGN_UP_ENABLED: "true"   # Disable after first user setup
      # Database:
      AP_POSTGRES_DATABASE: activepieces
      AP_POSTGRES_HOST: postgres
      AP_POSTGRES_PORT: 5432
      AP_POSTGRES_USERNAME: activepieces
      AP_POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
      AP_POSTGRES_USE_SSL: "false"
      # Redis:
      AP_REDIS_HOST: redis
      AP_REDIS_PORT: 6379
      # Encryption:
      AP_ENCRYPTION_KEY: "${ENCRYPTION_KEY}"
      AP_JWT_SECRET: "${JWT_SECRET}"

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: activepieces
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
      POSTGRES_DB: activepieces
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U activepieces"]
      interval: 10s
      start_period: 20s

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:
# .env
POSTGRES_PASSWORD=your-secure-db-password
ENCRYPTION_KEY=$(openssl rand -hex 16)   # Must be exactly 32 chars hex
JWT_SECRET=$(openssl rand -hex 32)

docker compose up -d

Visit https://flows.yourdomain.com → create admin account.


Part 2: HTTPS with Caddy

flows.yourdomain.com {
    reverse_proxy localhost:8080
}

Part 3: Building Flows

A flow in Activepieces is:

  • One trigger (webhook, schedule, or app event)
  • One or more steps (actions from pieces)

Create your first flow

  1. + New Flow
  2. Click Trigger → choose trigger type:
    • Webhook: Gets a unique URL for external services to call
    • Schedule: Cron expression (every hour, daily, etc.)
    • App trigger: Event from a specific app (new GitHub issue, Slack message, etc.)
  3. Click + to add steps
  4. Each step is a piece — choose app + action
  5. Reference data from previous steps using {{step_1.value}}

Part 4: Example Flows

GitHub stars → Slack notification

Trigger: Webhook (configure on GitHub as push event webhook)
  OR
Trigger: GitHub — New Star on Repository
  → Repo: your-org/your-repo

Step 1: Slack — Send Message
  Channel: #metrics
  Message: "🌟 New star! {{ trigger.stargazer.login }} starred {{ trigger.repository.full_name }}
            Total stars: {{ trigger.repository.stargazers_count }}"

Form → Google Sheets + email

Trigger: Webhook (POST from your contact form)

Step 1: Data transformation (using Code piece)
  Code: return {
    name: trigger.body.name,
    email: trigger.body.email,
    timestamp: new Date().toISOString()
  };

Step 2: Google Sheets — Insert Row
  Spreadsheet: "Contact Form Submissions"
  Sheet: "Leads"
  Values: {{ step1.name }}, {{ step1.email }}, {{ step1.timestamp }}

Step 3: Gmail — Send Email
  To: sales@yourcompany.com
  Subject: "New contact form submission from {{ step1.name }}"
  Body: "Name: {{ step1.name }}\nEmail: {{ step1.email }}"

Scheduled daily report

Trigger: Schedule — 0 9 * * 1-5 (weekdays at 9 AM)

Step 1: HTTP Request — GET https://yourapi.com/metrics
  Headers: Authorization: Bearer {{ connections.myapi.token }}

Step 2: Code — Format metrics
  Code: const data = step1.body;
        return {
          summary: `Users: ${data.users}, Revenue: $${data.revenue}`,
          html: `<b>Users:</b> ${data.users}<br><b>Revenue:</b> $${data.revenue}`
        };

Step 3: Slack — Send Message
  Channel: #daily-metrics
  Message: "📊 Daily Report\n{{ step2.summary }}"

Part 5: Webhook Triggers

# Your flow's webhook URL (from the trigger config panel):
https://flows.yourdomain.com/api/v1/webhooks/FLOW_ID

# Test a webhook:
curl -X POST https://flows.yourdomain.com/api/v1/webhooks/FLOW_ID \
  -H "Content-Type: application/json" \
  -d '{"event": "payment.completed", "amount": 99.99, "customer": "alice@example.com"}'

# Use as Stripe webhook:
# Stripe Dashboard → Developers → Webhooks → Add endpoint
# URL: https://flows.yourdomain.com/api/v1/webhooks/FLOW_ID
# Events: payment_intent.succeeded

# Use as GitHub webhook:
# Repo Settings → Webhooks → Add webhook
# Payload URL: https://flows.yourdomain.com/api/v1/webhooks/FLOW_ID
# Content type: application/json

Part 6: Custom TypeScript Pieces

If you need an integration that doesn't exist:

// packages/pieces/custom/my-service/src/lib/my-service.piece.ts
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
import { myServiceSendMessage } from './actions/send-message';
import { myServiceNewEvent } from './triggers/new-event';

export const MyServiceAuth = PieceAuth.SecretText({
  displayName: 'API Key',
  description: 'Your service API key',
  required: true,
});

export const myService = createPiece({
  displayName: 'My Service',
  auth: MyServiceAuth,
  minimumSupportedRelease: '0.20.0',
  logoUrl: 'https://yourservice.com/logo.png',
  authors: ['yourname'],
  actions: [myServiceSendMessage],
  triggers: [myServiceNewEvent],
});
// packages/pieces/custom/my-service/src/lib/actions/send-message.ts
import { createAction, Property } from '@activepieces/pieces-framework';
import { MyServiceAuth } from '../my-service.piece';

export const myServiceSendMessage = createAction({
  name: 'send_message',
  auth: MyServiceAuth,
  displayName: 'Send Message',
  description: 'Send a message via My Service',
  props: {
    recipient: Property.ShortText({ displayName: 'Recipient', required: true }),
    message: Property.LongText({ displayName: 'Message', required: true }),
  },
  async run(context) {
    const { recipient, message } = context.propsValue;
    const apiKey = context.auth;

    const response = await fetch('https://api.yourservice.com/messages', {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({ to: recipient, body: message }),
    });

    return response.json();
  },
});

Part 7: Connections (Credentials)

Manage credentials centrally in Connections:

  1. Connections → + New Connection
  2. Select a piece type (GitHub, Slack, Google, etc.)
  3. OAuth2 pieces: click Connect → authenticate
  4. API key pieces: enter your key
  5. All flows in your workspace can reuse connections

Maintenance

# Update Activepieces:
docker compose pull
docker compose up -d

# Backup database:
docker exec activepieces-postgres-1 pg_dump -U activepieces activepieces \
  | gzip > activepieces-backup-$(date +%Y%m%d).sql.gz

# Logs:
docker compose logs -f activepieces

# Disable new signups after admin setup:
# Set AP_SIGN_UP_ENABLED=false in docker-compose.yml then restart

See all open source automation tools at OSSAlt.com/categories/automation.

Comments