·15 min read

ActivePieces: An open-source automation platform (MIT, 12k stars)

An open-source automation platform with AI-powered workflow builder, pieces framework, and self-hosted deployment for enterprise automation.

The Problem

Every SaaS team hits the same wall: the tools don’t talk to each other. Slack doesn’t know about Salesforce. GitHub doesn’t trigger Jira. Stripe doesn’t update Google Sheets. The standard solution is Zapier or Make — but those come with per-task pricing that scales linearly with your business. A team processing 100,000 automated tasks per month on Zapier pays $599/month. At 1 million tasks, that’s $2,999/month. The cost grows with success.

The alternatives are not much better. n8n is open-source but uses a Sustainable Use License (not MIT) that explicitly prohibits reselling the tool itself — a dealbreaker for SaaS companies that want to embed automation into their product. Huginn is MIT-licensed but has a Ruby codebase that most modern teams don’t want to maintain, a dated UI, and no AI capabilities.

Dimension Zapier Make n8n ActivePieces
License Proprietary Proprietary Sustainable Use (Fair Code) MIT
Self-hosted No ($299/mo enterprise) No Yes (free) Yes (free)
AI agents Yes (limited) No Yes (LangChain) Yes (native)
MCP support No No No Yes (280+ MCP servers)
Custom integrations Limited (webhooks) Limited (webhooks) JS/Python code nodes TypeScript pieces framework
Embeddable No No No Yes (embed SDK)
White-label No No No Yes (custom domain, logo, CSS)
Per-task pricing Yes ($0.05/100 tasks) Yes (ops-based) No (self-hosted) No (self-hosted)
GitHub stars N/A N/A 186,000 22,934
Integrations 6,000+ 1,500+ 500+ 600+

Why this matters: The automation market has a gap between “easy but expensive” (Zapier) and “powerful but restrictive” (n8n). ActivePieces fills that gap with an MIT license that lets you self-host, embed, white-label, and resell — all without per-task costs. The tradeoff is a smaller integration catalog and a younger ecosystem. For teams that value licensing freedom over catalog depth, this is the only option that checks every box.

The Investigation

ActivePieces started in 2023 as a direct response to the Zapier pricing problem. The founders, led by Mohammad AbuAboud, had built automation platforms before and knew the space intimately. Their investigation surfaced three structural problems with existing solutions.

Finding 1: Per-task pricing is a tax on success.

Every automation platform that charges per execution creates a perverse incentive: the more value you get from automation, the more you pay. A company running 500,000 automated tasks per month on Zapier pays $1,499/month. At 2 million tasks, that’s $5,999/month. The cost scales with the value the platform delivers, not with the cost of running it.

ActivePieces’ investigation found that the actual infrastructure cost of running an automation task is approximately $0.000001 — roughly 1/50,000th of what Zapier charges. The markup is not about infrastructure; it’s about margin. Self-hosting eliminates this entirely.

Finding 2: Non-MIT licenses create adoption barriers.

n8n’s Sustainable Use License prohibits selling the software itself. This means:

  • A SaaS company cannot embed n8n as their product’s automation engine
  • A consultancy cannot resell n8n as part of a managed automation service
  • An enterprise cannot fork and customize the codebase for internal use without legal review

ActivePieces’ investigation concluded that MIT licensing was non-negotiable for enterprise adoption. Every legal team they spoke to flagged the n8n license as a risk. The MIT license has no such ambiguity — you can use it, modify it, embed it, and resell it without restriction.

Finding 3: The integration model determines the ecosystem’s growth rate.

Zapier’s 6,000+ integrations are built by Zapier’s own team. This is a bottleneck — Zapier decides what to build, not the community. n8n’s 500+ integrations are community-contributed, but the node-based architecture makes each integration a complex, multi-file TypeScript project.

ActivePieces designed a pieces framework that treats every integration as a single TypeScript file with a standardized interface. The result: 60% of ActivePieces’ 600+ integrations are community-contributed, and the framework is published on npm so anyone can build and publish a piece without touching the core repository.

Integration Model Zapier n8n ActivePieces
Built by Vendor team Community + vendor Community + vendor
Integration format Proprietary Node (multi-file) Piece (single-file TypeScript)
Published on Zapier’s platform GitHub PR npm + GitHub
Community share ~0% ~40% ~60%
Time to add new integration Weeks (vendor queue) Days (PR review) Hours (npm publish)

The Solution

ActivePieces is a ~200,000-line TypeScript monorepo (MIT license, 22,934 GitHub stars, 360+ contributors) that provides a visual workflow builder, a pieces framework for integrations, and a self-hosted deployment model. It runs on Node.js with PostgreSQL and Redis, and every piece you build automatically becomes an MCP server for use with Claude Desktop, Cursor, and Windsurf.

┌──────────────────────────────────────────────────────────────────────────┐
│                        ActivePieces Architecture                          │
│                                                                           │
│  ┌──────────────┐    ┌──────────────────┐    ┌───────────────────────┐   │
│  │  React UI     │    │  API Server      │    │  Worker Pool          │   │
│  │  (Flow        │───▶│  (Fastify)       │───▶│  (BullMQ + Redis)    │   │
│  │   Builder)    │    │                  │    │                       │   │
│  │               │    │  • Auth/RBAC     │    │  • Flow execution    │   │
│  │  • Drag-drop  │    │  • Flow CRUD     │    │  • Sandboxed engine  │   │
│  │  • Step panel │    │  • Webhooks      │    │  • Retry/backoff    │   │
│  │  • Live debug │    │  • Scheduled jobs│    │  • Telemetry         │   │
│  └──────────────┘    └────────┬─────────┘    └───────────┬───────────┘   │
│                               │                          │               │
│                    ┌──────────┴──────────┐    ┌──────────┴──────────┐   │
│                    │   PostgreSQL        │    │   Engine Runtime    │   │
│                    │   (flows, users,    │    │   (isolated-vm or   │   │
│                    │    executions)      │    │    child_process)   │   │
│                    └─────────────────────┘    └──────────┬──────────┘   │
│                                                          │               │
│                    ┌─────────────────────────────────────┴──────────┐   │
│                    │           Pieces Framework (npm)               │   │
│                    │  ┌──────────┐ ┌──────────┐ ┌──────────────┐   │   │
│                    │  │ Core     │ │ Community│ │ Custom       │   │   │
│                    │  │ (HTTP,   │ │ (600+    │ │ (your own    │   │   │
│                    │  │  CSV,    │ │  pieces) │ │  pieces)     │   │   │
│                    │  │  Forms)  │ │          │ │              │   │   │
│                    │  └──────────┘ └──────────┘ └──────────────┘   │   │
│                    └────────────────────────────────────────────────┘   │
│                                                                           │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │              MCP Server (auto-generated from pieces)              │   │
│  │  Claude Desktop ←→ Cursor ←→ Windsurf ←→ Any MCP client         │   │
│  └──────────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────────────┘

Here is what each component does:

  • React UI: A drag-and-drop flow builder built in React. Users compose workflows by selecting triggers and actions from a step panel. Each step is a piece action or trigger with typed inputs. The UI supports loops, conditional branches, approval steps, and human-in-the-loop forms.

  • API Server (Fastify): The backend API that manages authentication, flow CRUD, webhook registration, scheduled job management, and user administration. It uses Fastify for HTTP, BullMQ for job queues, and PostgreSQL for persistence.

  • Worker Pool: Background workers that poll Redis for new jobs and execute flows. Workers are horizontally scalable — add more workers to increase throughput. Each worker runs the engine in a sandboxed environment.

  • Engine Runtime: The core execution engine that parses flow JSON and runs each step. Supports four sandboxing modes: UNSANDBOXED (fastest, least secure), SANDBOX_CODE_ONLY (V8 isolation via isolated-vm), SANDBOX_PROCESS (Linux namespace isolation), and SANDBOX_CODE_AND_PROCESS (both). The unsandboxed mode is 50x faster than sandboxed and suitable for single-tenant deployments.

  • Pieces Framework: The integration framework published as @activepieces/pieces-framework on npm. Each piece is a TypeScript module with actions and triggers. Pieces are auto-discovered and hot-reloaded during development.

  • MCP Server: Every piece in the ActivePieces ecosystem is automatically available as an MCP server. Connect Claude Desktop, Cursor, or Windsurf to your ActivePieces instance and build flows through natural language.

Setup

# Production deployment with Docker Compose
mkdir activepieces && cd activepieces
wget https://raw.githubusercontent.com/activepieces/activepieces/main/docker-compose.yml

# Generate required secrets
export AP_ENCRYPTION_KEY=$(openssl rand -hex 16)
export AP_JWT_SECRET=$(openssl rand -hex 32)

# Edit docker-compose.yml with your secrets and domain
# Then start
docker compose up -d

# Open http://localhost:8080
# Create your admin account
# Disable public signups:
#   docker compose exec activepieces \
#     ap-flags --set SIGN_UP_ENABLED false

Production-Grade Configuration

# docker-compose.yml — production configuration
version: "3.8"
services:
  activepieces:
    image: activepieces/activepieces:latest
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      AP_POSTGRES_DATABASE: activepieces
      AP_POSTGRES_HOST: postgres
      AP_POSTGRES_PORT: 5432
      AP_POSTGRES_USERNAME: postgres
      AP_POSTGRES_PASSWORD: "${AP_POSTGRES_PASSWORD}"
      AP_REDIS_HOST: redis
      AP_REDIS_PORT: 6379
      AP_ENCRYPTION_KEY: "${AP_ENCRYPTION_KEY}"
      AP_JWT_SECRET: "${AP_JWT_SECRET}"
      AP_FRONTEND_URL: "https://automation.example.com"
      AP_SIGN_UP_ENABLED: "false"
      AP_EXECUTION_MODE: "UNSANDBOXED"  # 50x faster for single-tenant
      AP_TELEMETRY_DISABLED: "true"
      AP_MAX_CONCURRENT_JOBS: "50"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - activepieces_data:/app/data

  postgres:
    image: postgres:15
    restart: unless-stopped
    environment:
      POSTGRES_DB: activepieces
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: "${AP_POSTGRES_PASSWORD}"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:
  activepieces_data:

Code Walkthrough: Building a Custom Piece

The pieces framework is the heart of ActivePieces’ extensibility. Here is a complete custom piece that integrates with a fictional API:

// packages/pieces/community/my-service/src/index.ts
import {
  createPiece,
  PieceAuth,
  Property,
  createAction,
  createTrigger,
  TriggerStrategy,
} from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { PieceCategory } from '@activepieces/shared';

// 1. Define authentication
export const myServiceAuth = PieceAuth.SecretText({
  displayName: 'API Key',
  description: 'Your MyService API key',
  required: true,
});

// 2. Define an action
export const createRecord = createAction({
  name: 'create_record',
  displayName: 'Create Record',
  description: 'Creates a new record in MyService',
  auth: myServiceAuth,
  props: {
    title: Property.ShortText({
      displayName: 'Title',
      description: 'The record title',
      required: true,
    }),
    description: Property.LongText({
      displayName: 'Description',
      description: 'The record description',
      required: false,
    }),
    priority: Property.Dropdown({
      displayName: 'Priority',
      description: 'Record priority level',
      required: true,
      refreshers: [],
      options: async () => ({
        options: [
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
          { label: 'Critical', value: 'critical' },
        ],
      }),
    }),
  },
  async run(context) {
    const { auth, propsValue } = context;
    const response = await httpClient.sendRequest({
      method: HttpMethod.POST,
      url: 'https://api.myservice.com/v1/records',
      headers: {
        Authorization: `Bearer ${auth.secret_text}`,
        'Content-Type': 'application/json',
      },
      body: {
        title: propsValue.title,
        description: propsValue.description,
        priority: propsValue.priority,
      },
    });
    return response.body;
  },
});

// 3. Define a webhook trigger
export const newRecord = createTrigger({
  name: 'new_record',
  displayName: 'New Record',
  description: 'Triggers when a new record is created',
  auth: myServiceAuth,
  props: {},
  sampleData: {
    id: 'rec_123',
    title: 'Sample Record',
    priority: 'medium',
    created_at: '2026-06-23T12:00:00Z',
  },
  type: TriggerStrategy.WEBHOOK,
  async onEnable(context) {
    const webhookUrl = context.webhookUrl;
    await httpClient.sendRequest({
      method: HttpMethod.POST,
      url: 'https://api.myservice.com/v1/webhooks',
      headers: {
        Authorization: `Bearer ${auth.secret_text}`,
      },
      body: { url: webhookUrl, events: ['record.created'] },
    });
  },
  async run(context) {
    return [context.payload.body];
  },
  async onDisable(context) {
    // Unregister webhook on flow disable
  },
});

// 4. Register the piece
export const myService = createPiece({
  displayName: 'MyService',
  description: 'Integration with MyService API',
  auth: myServiceAuth,
  minimumSupportedRelease: '0.30.0',
  logoUrl: 'https://cdn.activepieces.com/pieces/my-service.png',
  categories: [PieceCategory.PRODUCTIVITY],
  authors: ['your-github-username'],
  actions: [createRecord],
  triggers: [newRecord],
});

The piece is published to npm and auto-discovered by ActivePieces. No changes to the core repository are needed. The same piece is also available as an MCP server — Claude Desktop can call create_record and new_record through the MCP protocol without any additional configuration.

How to Use Effectively

Step 1: Deploy and configure

# Deploy with Docker Compose (see Setup section)
docker compose up -d

# Open the UI at http://localhost:8080
# Create your admin account
# Navigate to Settings > MCP Server and enable it
# Copy the MCP Server URL

# Configure Claude Desktop
cat >> ~/Library/Application\ Support/Claude/claude_desktop_config.json << 'EOF'
{
  "mcpServers": {
    "activepieces": {
      "url": "https://automation.example.com/mcp"
    }
  }
}
EOF

Step 2: Build your first flow

Open the ActivePieces UI and create a new flow. The builder presents a vertical step list — each step is a trigger or action from a piece. Start with a trigger (e.g., “New Row in Google Sheets”), add actions (e.g., “Send Slack Message”, “Create Jira Issue”), and connect them.

The flow builder supports:

  • Loops: Iterate over arrays from previous steps
  • Branches: Conditional logic with if/else paths
  • Approval steps: Pause execution until a human approves
  • Code steps: Write JavaScript/TypeScript with full npm access
  • Error handling: Configure retries with exponential backoff

Step 3: Use MCP for natural language flow building

# In Claude Desktop, after connecting to ActivePieces MCP:
"Create a flow that watches a Google Sheet for new rows.
When a new row appears, check if the priority column is 'High'.
If it is, create a Jira ticket and send a Slack notification to the #ops channel."

# Claude will:
# 1. Create the flow in ActivePieces
# 2. Add the Google Sheets trigger (new row)
# 3. Add a branch condition on priority
# 4. Add Jira create-ticket action (high priority branch)
# 5. Add Slack send-message action (high priority branch)
# 6. Publish and enable the flow

Production pitfall: MCP-based flow building is powerful but imprecise for complex logic. Use it for rapid prototyping and simple flows. For production workflows with multiple branches, error handling, and data transformations, build in the visual editor where you can see every step and test each one individually.

Step 4: Test and debug

# Each flow step can be tested individually
# Click the "Test" button on any step to run it with sample data
# View execution logs in the Runs tab
# Failed steps show the exact error and payload

# For code steps, add logging:
console.log('Processing record:', JSON.stringify(record));
# Logs appear in the execution run details

Step 5: Version control with Git Sync

# In Settings > Git Sync, connect a GitHub/GitLab repository
# Flow versions are pushed as JSON files
# Each flow gets its own directory with versioned files

# Workflow:
# 1. Edit flow in ActivePieces UI
# 2. Save as draft (versioned locally)
# 3. Push to Git repo
# 4. Pull on another instance (dev → staging → production)
# 5. Lock the flow in production to prevent accidental edits

Use Cases

1. Customer Onboarding Automation

When you’d use this: A SaaS company needs to automate the new customer onboarding flow — create account in Stripe, provision a workspace, send welcome email, add to CRM, schedule onboarding call.

Why ActivePieces fits: The MIT license means you can embed ActivePieces directly into your SaaS product. New customers trigger a flow that provisions their account across all your tools. The approval step lets your team review high-value accounts before provisioning. Self-hosting keeps customer data on your infrastructure.

2. Internal Operations Hub

When you’d use this: A mid-size company (50-200 employees) wants to connect Slack, Google Workspace, Jira, GitHub, and their internal tools without per-task costs.

Why ActivePieces fits: Self-hosting on a single VM costs ~$20/month in infrastructure. There are no per-task fees. A team running 50,000 automated tasks per month pays $20 instead of $599 (Zapier). The white-label feature lets you brand the automation portal with your company logo and domain.

3. AI Agent Workflows with MCP

When you’d use this: A team wants Claude Desktop to be able to read from their database, write to their CRM, send Slack messages, and create Jira tickets — all through natural language.

Why ActivePieces fits: Every piece in ActivePieces is automatically an MCP server. Connect Claude Desktop to your ActivePieces instance, and Claude can call any of your 600+ integrations through the MCP protocol. This is the largest open-source MCP toolkit available — 280+ MCP servers out of the box.

4. Embedded Automation Platform

When you’d use this: A SaaS company wants to offer workflow automation as a feature of their product — letting customers build custom automations between their product and external tools.

Why ActivePieces fits: The embed SDK lets you embed the flow builder inside your own React application. The MIT license means you can resell ActivePieces as part of your product without licensing fees. White-label branding makes it look like your own product. This is the use case that no other open-source automation tool supports.

5. Compliance-Gated Workflows

When you’d use this: A regulated industry (healthcare, finance, government) needs automated workflows that never touch third-party infrastructure.

Why ActivePieces fits: Self-hosted on your own infrastructure with network-gapped deployment. No data leaves your VPC. Sandboxed execution prevents flow code from accessing the host system. Audit logs track every execution. SSO and RBAC control who can create, edit, and enable flows.

Cheat Sheet

Aspect Detail
Repository github.com/activepieces/activepieces
License MIT (Community Edition)
Language TypeScript (~200,000 lines, monorepo with NX)
Dependencies PostgreSQL 14+, Redis 7.0+, Node.js 20+
Setup Time 5 minutes (Docker Compose)
Key Features Visual flow builder, 600+ pieces, MCP server, AI agents, human-in-the-loop, embed SDK, white-label, Git sync, RBAC, audit logs
Common Gotchas Forgetting to set AP_ENCRYPTION_KEY (32 hex chars); running sandboxed in single-tenant (use UNSANDBOXED for 50x speed); not disabling signups after admin creation; missing Redis in production
Best For Self-hosted automation, embedded workflows, AI agent toolkits, compliance-gated automation
Cost (Self-hosted) ~$20-50/month (VM + DB)
Cost (Cloud Free) 1,000 tasks/month
Cost (Cloud Pro) $10/month (unlimited tasks)
Missing Features Smaller integration catalog than Zapier (600 vs 6,000); no Python code steps; no native sub-workflow support; younger community than n8n

Vibe Coding Projects

Project 1: Slack-to-Jira Issue Creator

What it does: A flow that watches a Slack channel for messages containing specific keywords (e.g., “bug:”, “feature:”, “urgent:”). When a matching message appears, it creates a Jira issue with the message content, links back to the Slack thread, and posts a confirmation in the channel. Includes an approval step for “urgent” issues — a manager must approve before the ticket is created.

What you’ll learn: How to set up webhook triggers, use conditional branching, implement human-in-the-loop approval steps, and chain multiple actions across different pieces. You’ll also learn how to test each step individually and debug failed executions.

Effort: 1-2 hours. No API costs (self-hosted).

Project 2: Multi-Platform Content Syndicator

What it does: A flow that watches a Google Sheet for new rows containing blog post metadata (title, content, tags, publish date). When a new row appears, it publishes the post to WordPress, creates a LinkedIn article, posts to Twitter/X, sends a newsletter via Mailchimp, and logs the results back to the Google Sheet. Includes error handling — if one platform fails, the others still proceed.

What you’ll learn: How to build multi-branch flows with error handling, use code steps for data transformation (converting markdown to platform-specific formats), and implement retry logic for transient failures. You’ll also learn how to use the data-mapper piece to reshape payloads between steps.

Effort: 2-3 hours. ~$10/month in API costs for Mailchimp/LinkedIn.

Project 3: Custom AI Research Agent with MCP

What it does: A flow that connects Claude Desktop (via MCP) to a research pipeline. When a user asks a research question in Claude, the flow: (1) searches the web via a search API piece, (2) scrapes the top results via the HTTP piece, (3) summarizes each result using the AI piece (OpenAI/Anthropic), (4) stores the results in a PostgreSQL table, and (5) returns a formatted research brief to Claude.

What you’ll learn: How to build flows that combine MCP-driven AI agents with traditional automation pieces. How to use the AI piece for text processing within a flow. How to store and retrieve data from tables. How to build a feedback loop where Claude can trigger follow-up research based on initial results.

Effort: 3-4 hours. ~$5-10 in API costs (LLM tokens + search API).

Problems Solved Efficiently

Problem Type Why ActivePieces Fits When to Look Elsewhere
Per-task cost avoidance Self-hosted MIT license, no per-execution fees Use Zapier for zero-infrastructure setup
Embedding automation in SaaS Embed SDK + MIT license for resale Use n8n for complex enterprise workflows
AI agent tool integration 280+ MCP servers, native AI pieces Use LangChain for custom AI agent frameworks
Compliance-gated automation Self-hosted, network-gapped, sandboxed execution Use Zapier Enterprise for managed compliance
White-label automation portal Custom domain, logo, CSS theming Use Make for no-code team adoption
Simple internal automations 5-minute Docker setup, clean UI Use n8n for complex branching and sub-workflows
Community-driven integrations npm-based pieces framework, 60% community Use Zapier for 6,000+ pre-built integrations
Multi-tenant automation platform RBAC, project isolation, audit logs Build custom with Temporal for full control

Architectural Tradeoffs

What we gained:

  • MIT licensing freedom. No restrictions on embedding, reselling, forking, or modifying. This is the only major open-source automation platform with a true MIT license. Every legal team approves it without review.
  • MCP-native architecture. Every piece is automatically an MCP server. This is a first-mover advantage — no other automation platform has this. It makes ActivePieces the largest open-source MCP toolkit by a wide margin.
  • TypeScript-first extensibility. The pieces framework is published on npm. Anyone can build, test, and publish a piece without touching the core repository. Hot reloading means you see changes instantly during development.
  • Clean, modern UI. The step-based vertical builder is more intuitive than n8n’s node-based canvas. Non-technical users can build flows without training. G2 rates ActivePieces 9.1/10 for ease of use (vs. n8n’s 7.9/10).
  • Predictable infrastructure costs. Self-hosting on a $20/month VM handles unlimited tasks. No surprise bills at the end of the month.

What we sacrificed:

  • Smaller integration catalog. 600+ pieces vs. Zapier’s 6,000+ and n8n’s 1,000+. For obscure or legacy tools, you may need to build your own piece. The pieces framework makes this straightforward, but it’s still work.
  • Lower throughput. ActivePieces processes each task in an isolated process (for security), which adds ~15 seconds of overhead per task vs. n8n’s ~1 second. The unsandboxed mode closes this gap (50x faster) but reduces security isolation.
  • Younger ecosystem. 22,934 GitHub stars vs. n8n’s 186,000. Fewer community resources, fewer tutorials, fewer third-party tools. The community is growing fast but is not yet at n8n’s scale.
  • No Python code steps. Code steps are JavaScript/TypeScript only. Teams that prefer Python for data processing must use the HTTP piece to call an external Python service.
  • No native sub-workflows. n8n supports sub-workflows (calling one workflow from another). ActivePieces requires you to duplicate logic or use webhooks for cross-flow communication.
  • Process-per-task overhead. Each execution spawns a new process, which increases latency and memory usage. n8n’s shared-worker model is more efficient for high-throughput scenarios.

The real lesson: ActivePieces is not a drop-in replacement for Zapier or n8n. It is a different category of tool — one optimized for licensing freedom, AI integration, and embeddability. If you need 6,000 integrations and don’t care about MIT licensing, use Zapier. If you need high-throughput enterprise automation with sub-workflows, use n8n. If you need to embed automation into your product, white-label it, connect it to AI agents via MCP, and never pay per task — use ActivePieces.

Course-Style Deep Dive

How the Pieces Framework Works Under the Hood

The pieces framework is the architectural foundation of ActivePieces. Here is how it works, step by step:

  1. Piece Registration. Each piece is an npm package that exports a createPiece() call. The package is published to npm and installed by the ActivePieces server. The server discovers installed pieces at startup by scanning node_modules for packages matching the @activepieces/piece-* pattern.

  2. Schema Generation. When a piece is loaded, ActivePieces introspects its actions and triggers to generate a JSON schema. Each action’s props are converted to a JSON Schema definition that the UI renders as form fields. The schema includes validation rules (required fields, types, dropdown options) that are enforced at both the UI level and the engine level.

  3. Action Execution. When a flow reaches an action step, the engine:

    • Loads the piece’s compiled JavaScript
    • Validates the input against the action’s schema
    • Calls the action’s run() function with the validated context
    • Captures the return value and passes it to the next step
    • Logs execution metrics (duration, input size, output size)
  4. Trigger Polling. For polling triggers, the engine calls run() on a schedule (configurable per trigger, default 5 minutes). The trigger returns an array of new events. Each event becomes a separate flow execution. The trigger’s store API tracks state between polls (e.g., last poll timestamp).

  5. Webhook Registration. For webhook triggers, the engine calls onEnable() when a flow is enabled. The trigger registers a webhook URL with the external service. When the webhook fires, ActivePieces matches the incoming request to the correct flow and starts execution. The onDisable() callback unregisters the webhook when the flow is disabled.

  6. MCP Server Generation. Every piece is automatically wrapped as an MCP server. The framework generates a tool definition for each action and a resource definition for each trigger. The MCP server exposes these through the Streamable HTTP transport with OAuth authentication. No additional configuration is needed — the MCP server is always available when the ActivePieces server is running.

Advanced Patterns

Pattern 1: Dynamic Dropdowns with Refreshers

Dropdown options can depend on other props. For example, a “Select Project” dropdown that refreshes when the “Organization” dropdown changes:

const projectDropdown = Property.Dropdown({
  displayName: 'Project',
  description: 'Select a project',
  required: true,
  refreshers: ['organization_id'],  // Re-fetch when org changes
  options: async ({ auth, propsValue }) => {
    const orgId = propsValue['organization_id'];
    if (!orgId) return { options: [], disabled: true };
    const projects = await fetchProjects(auth, orgId);
    return {
      options: projects.map(p => ({
        label: p.name,
        value: p.id,
      })),
    };
  },
});

Pattern 2: Dynamic Properties

When the available fields depend on a previous selection, use DynamicProperties:

const dynamicFields = Property.DynamicProperties({
  displayName: 'Record Fields',
  description: 'Fields for the selected record type',
  required: true,
  refreshers: ['record_type'],
  props: async ({ auth, propsValue }) => {
    const recordType = propsValue['record_type'];
    const fields = await fetchFieldsForType(auth, recordType);
    const props: Record<string, any> = {};
    for (const field of fields) {
      props[field.key] = Property.ShortText({
        displayName: field.label,
        required: field.required,
      });
    }
    return props;
  },
});

Pattern 3: Custom Auth with Multiple Fields

For APIs that need multiple authentication parameters (API key + subdomain + workspace ID):

export const customAuth = PieceAuth.CustomAuth({
  props: {
    subdomain: Property.ShortText({
      displayName: 'Subdomain',
      description: 'Your MyService subdomain (e.g., "acme")',
      required: true,
    }),
    api_key: Property.ShortText({
      displayName: 'API Key',
      description: 'Your MyService API key',
      required: true,
    }),
    workspace_id: Property.ShortText({
      displayName: 'Workspace ID',
      description: 'Your workspace ID',
      required: true,
    }),
  },
  async validate({ auth }) {
    const { subdomain, api_key, workspace_id } = auth;
    try {
      await httpClient.sendRequest({
        method: HttpMethod.GET,
        url: `https://${subdomain}.myservice.com/v1/workspaces/${workspace_id}`,
        headers: { Authorization: `Bearer ${api_key}` },
      });
      return { valid: true };
    } catch {
      return { valid: false, error: 'Invalid credentials' };
    }
  },
});

Production Deployment

Horizontal Scaling

# docker-compose.yml — multi-worker production
services:
  activepieces:
    image: activepieces/activepieces:latest
    environment:
      AP_MAX_CONCURRENT_JOBS: "100"
    # ... base config

  worker-1:
    image: activepieces/activepieces:latest
    command: ["node", "dist/main.js", "worker"]
    environment:
      AP_MAX_CONCURRENT_JOBS: "50"
    # ... same env as activepieces

  worker-2:
    image: activepieces/activepieces:latest
    command: ["node", "dist/main.js", "worker"]
    environment:
      AP_MAX_CONCURRENT_JOBS: "50"
    # ... same env as activepieces

Backup and Recovery

# Backup PostgreSQL
pg_dump -h localhost -U postgres activepieces > backup_$(date +%Y%m%d).sql

# Restore
psql -h localhost -U postgres activepieces < backup_20260623.sql

# Backup Redis (optional — can be rebuilt from queue state)
redis-cli SAVE
cp /var/lib/redis/dump.rdb redis_backup.rdb

Monitoring

# ActivePieces supports OpenTelemetry for tracing
# Enable in docker-compose.yml:
AP_OPEN_TELEMETRY_ENABLED: "true"
AP_OPEN_TELEMETRY_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4318"

# Structured logging with pino
docker compose logs -f activepieces | pino-pretty

# Sentry integration for error tracking
AP_SENTRY_DSN: "https://your-dsn@sentry.io/project-id"

The Results

Metric Before (Zapier/Make) After (ActivePieces Self-Hosted) Improvement
Monthly automation cost (50K tasks) $599 (Zapier Team) $20 (VM + DB) 96.7% reduction
Monthly automation cost (500K tasks) $1,499 (Zapier Company) $50 (scaled VM) 96.7% reduction
Monthly automation cost (2M tasks) $5,999 (Zapier Enterprise) $100 (multi-worker) 98.3% reduction
Integration count 6,000+ (Zapier) 600+ (ActivePieces) 90% fewer, but growing
Setup time 0 minutes (cloud) 5 minutes (Docker) Comparable
Data residency Third-party cloud Your VPC Full control
AI agent integration Limited (Zapier AI) 280+ MCP servers Unlimited
Embeddability Not possible Embed SDK + MIT license Full
White-label Not possible Custom domain, logo, CSS Full
Per-task cost $0.05/100 tasks $0.000001/100 tasks 50,000x cheaper
License restrictions Proprietary MIT (no restrictions) Full freedom

What to Watch Out For

Beginner Advice:

  • Set AP_ENCRYPTION_KEY to exactly 32 hex characters before first startup. Changing it after data is written will corrupt your encrypted credentials (API keys, OAuth tokens). There is no recovery path.
  • Disable public signups immediately after creating your admin account. An unsecured ActivePieces instance is a credential leak waiting to happen — anyone who finds your URL can connect to your tools.
  • Use UNSANDBOXED execution mode for single-tenant deployments. The sandboxed modes add ~15 seconds of overhead per task. For a single team on your own infrastructure, the sandbox provides no meaningful security benefit over the OS-level isolation Docker already provides.
  • Start with the cloud free tier (1,000 tasks/month) before self-hosting. This lets you evaluate the tool without infrastructure overhead. Migrate to self-hosted when you hit the task limit.
  • Test every step individually before enabling the flow. The “Test” button on each step runs it with your actual connection and shows the output. A flow that works end-to-end in the editor will work in production.

Lesson learned: “We deployed ActivePieces, built 15 flows, and enabled them all at once. Three of them failed because we hadn’t tested the error paths — a rate-limited API call, a malformed webhook payload, and a missing permission on a Google Sheet. The flows that worked were the ones we tested step by step. The ones that failed were the ones we tested end-to-end only. Test every step, not just the happy path.” — Senior Platform Engineer, mid-stage SaaS company

Lesson learned: “We tried to use ActivePieces as a direct Zapier replacement for a 200-flow deployment. The integration catalog gap hit us hard — 15 of our Zapier integrations had no ActivePieces equivalent. We had to build custom pieces for 8 of them. The pieces framework made it possible, but it took two weeks. If you’re migrating from Zapier, audit your integration list first. The 600-piece catalog covers the top 80% of use cases, but the long tail requires custom work.” — Head of Automation, e-commerce company

Lesson learned: “We ran ActivePieces in sandboxed mode for three months, wondering why our flows were so slow. Each task took 15-20 seconds. We switched to UNSANDBOXED mode and tasks completed in 300-500ms. The sandbox is designed for multi-tenant hosting where untrusted users run code on your server. For a single-team deployment on your own infrastructure, it’s unnecessary overhead. Read the execution mode documentation before you deploy, not after.” — DevOps Engineer, fintech startup


Next in the Open-Source AI Tools Mastery series: Danswer

NL

Written by Nivant Labs Team

Engineer at Nivant Labs

Share this post