Skip to main content
Activepieces maintains a complete version history of your workflows, allowing you to track changes, compare versions, and rollback when needed.

Understanding Flow Versions

Every flow has multiple versions over its lifetime:
// From packages/shared/src/lib/automation/flows/flow-version.ts
export const LATEST_FLOW_SCHEMA_VERSION = '16'

export type FlowVersion = {
  id: string,
  flowId: string,
  displayName: string,
  trigger: FlowTrigger,
  valid: boolean,
  schemaVersion: string | null,
  state: FlowVersionState.DRAFT | FlowVersionState.LOCKED,
  created: string,
  updated: string,
  updatedBy: string | null
}

Draft Version

Your working copy. Only one draft exists per flow. Editable and unpublished.

Locked Versions

Published versions. Immutable historical records. Multiple can exist.

Version States

export enum FlowVersionState {
  LOCKED = 'LOCKED',  // Published, immutable
  DRAFT = 'DRAFT'     // Editable, unpublished
}
  • One per flow: Only the current working version
  • Editable: Can be modified at any time
  • Unpublished: Not running in production
  • Overwritten: Changes overwrite the draft
{
  "state": "DRAFT",
  "valid": true,
  "updated": "2024-03-15T10:30:00Z",
  "updatedBy": "user-123"
}

Version Lifecycle

1

Create Flow

When you create a new flow, a draft version is created:
// From packages/server/api/src/app/flows/flow-version/flow-version.service.ts
async createEmptyVersion(flowId: FlowId, request: {
  displayName: string,
  notes: Note[]
}): Promise<FlowVersion> {
  const flowVersion: NewFlowVersion = {
    id: apId(),
    displayName: request.displayName,
    flowId,
    trigger: {
      type: FlowTriggerType.EMPTY,
      name: 'trigger',
      settings: {},
      valid: false,
      displayName: 'Select Trigger'
    },
    schemaVersion: LATEST_FLOW_SCHEMA_VERSION,
    connectionIds: [],
    agentIds: [],
    valid: false,
    state: FlowVersionState.DRAFT,
    notes: request.notes
  };
  return flowVersionRepo().save(flowVersion);
}
2

Edit Draft

Make changes to the draft version. Changes are auto-saved:
// Each edit updates the draft
{
  "state": "DRAFT",
  "updated": "2024-03-15T10:30:00Z",
  "trigger": { /* updated trigger */ },
  // ... modified actions
}
3

Publish

Publishing creates a new locked version:
// Draft becomes a locked version
{
  "state": "LOCKED",
  "created": "2024-03-15T10:35:00Z",
  "valid": true
  // Exact copy of draft at publish time
}

// Draft continues to exist for further edits
4

Continue Editing

After publishing, continue editing the draft:
// Draft can be modified while locked version runs
{
  "state": "DRAFT",
  "updated": "2024-03-15T11:00:00Z",
  // New changes
}
5

Publish Again

Each publish creates a new locked version:
// Version history grows
[
  { "id": "v1", "state": "LOCKED", "created": "2024-03-15T10:35:00Z" },
  { "id": "v2", "state": "LOCKED", "created": "2024-03-15T11:30:00Z" },
  { "id": "v3", "state": "LOCKED", "created": "2024-03-15T14:00:00Z" },
  { "id": "draft", "state": "DRAFT", "updated": "2024-03-15T15:00:00Z" }
]

Viewing Version History

Version List

Access the version history from the flow builder:
// From packages/server/api/src/app/flows/flow-version/flow-version.service.ts
async list({
  flowId,
  cursorRequest,
  limit
}): Promise<SeekPage<FlowVersion>> {
  const paginator = buildPaginator({
    entity: FlowVersionEntity,
    query: {
      limit,
      order: 'DESC',  // Newest first
      afterCursor: decodedCursor.nextCursor,
      beforeCursor: decodedCursor.previousCursor
    }
  });
  
  const paginationResult = await paginator.paginate(
    flowVersionRepo().createQueryBuilder()
      .where({ flowId })
  );
  
  // Include user information
  const versions = await Promise.all(
    paginationResult.data.map(async (flowVersion) => ({
      ...flowVersion,
      updatedByUser: flowVersion.updatedBy 
        ? await userService.getMetaInformation({ id: flowVersion.updatedBy })
        : null
    }))
  );
  
  return paginationHelper.createPage(versions, paginationResult.cursor);
}
Versions are listed newest to oldest, with user information showing who made changes.

Version Metadata

// From packages/shared/src/lib/automation/flows/flow-version.ts
export type FlowVersionMetadata = {
  id: string,
  flowId: string,
  displayName: string,
  valid: boolean,
  state: FlowVersionState,
  updatedBy: string | null,
  schemaVersion: string | null,
  updatedByUser: UserWithMetaInformation | null,
  created: string,
  updated: string
}
Each version shows:
  • Version ID: Unique identifier
  • Display Name: Flow name at that version
  • Valid: Whether all steps were valid
  • Updated By: User who created this version
  • Timestamp: When version was created
  • Schema Version: Flow schema version number

Using Version History

View a Previous Version

1

Open Version Selector

Click the version dropdown in the flow builder.
2

Select Version

Choose any locked version to view.
3

View Read-Only

The version opens in read-only mode:
// From packages/web/src/app/builder/builder-hooks.ts
{
  "readonly": true,  // Cannot edit locked versions
  "flowVersion": { /* locked version data */ }
}
4

Return to Draft

Click “Edit Flow” to return to the draft version.

Use Version as Draft

Restore a previous version to your draft:
// From packages/server/api/src/app/flows/flow-version/flow-version.service.ts
case FlowOperationType.USE_AS_DRAFT: {
  const previousVersion = await flowVersionService.getFlowVersionOrThrow({
    flowId: flowVersion.flowId,
    versionId: userOperation.request.versionId,
    removeConnectionsName: false
  });
  
  operations = [{
    type: FlowOperationType.IMPORT_FLOW,
    request: {
      trigger: previousVersion.trigger,
      displayName: previousVersion.displayName,
      schemaVersion: previousVersion.schemaVersion,
      notes: previousVersion.notes
    }
  }];
  break;
}
1

View Previous Version

Select the version you want to restore.
2

Click 'Use as Draft'

This copies the version to your draft.
3

Review Changes

The draft now matches the selected version.
4

Publish (Optional)

If satisfied, publish to make it the active version.
Using a version as draft overwrites your current draft. Ensure you don’t have unpublished changes you want to keep.

Rollback Capabilities

Rollback to Previous Version

To rollback to a previous version:
  1. Open version history
  2. Select the version to restore
  3. Click “Use as Draft”
  4. Click “Publish” immediately
  5. Flow now runs the restored version
// Two operations:
// 1. Copy old version to draft
// 2. Publish draft

Version Comparison

While Activepieces doesn’t have built-in visual diff, you can compare versions:
1

Open First Version

View the first version you want to compare.
2

Note Key Differences

Review:
  • Trigger configuration
  • Number of actions
  • Action settings
  • Error handling options
3

Open Second Version

Switch to the other version.
4

Compare

Note differences in:
  • Step configuration
  • Data mappings
  • Connections used
Future versions of Activepieces may include visual diff tools for comparing versions.

Schema Versions

Flow versions track the schema version:
// From packages/shared/src/lib/automation/flows/flow-version.ts
export const LATEST_FLOW_SCHEMA_VERSION = '16'

export type FlowVersion = {
  schemaVersion: string | null,  // e.g., "16"
  // ...
}
Schema versions track:
  • Flow structure format changes
  • New features added
  • Breaking changes

Schema Migration

Old versions are automatically migrated:
// From packages/server/api/src/app/flows/flow-version/flow-version-migration.service.ts
async migrate(flowVersion: FlowVersion): Promise<FlowVersion> {
  if (flowVersion.schemaVersion === LATEST_FLOW_SCHEMA_VERSION) {
    return flowVersion;
  }
  
  // Apply migrations to bring to latest schema
  let migrated = flowVersion;
  
  // Migration chain: v1 -> v2 -> v3 -> ... -> v16
  for (const migration of migrations) {
    if (shouldApplyMigration(migrated.schemaVersion, migration.version)) {
      migrated = await migration.migrate(migrated);
    }
  }
  
  migrated.schemaVersion = LATEST_FLOW_SCHEMA_VERSION;
  return migrated;
}
Schema migrations are automatic and backward-compatible. Old versions continue to work.

Version Metadata Tracking

Updated By User

// From packages/shared/src/lib/automation/flows/flow-version.ts
export type FlowVersionMetadata = {
  updatedBy: string | null,
  updatedByUser: UserWithMetaInformation | null  // User details
}

export type UserWithMetaInformation = {
  id: string,
  email: string,
  firstName: string,
  lastName: string,
  // ...
}
Track who made changes:
  • User ID: Who created this version
  • User Info: Full user details (name, email)
  • Timestamp: When version was created

Connection Tracking

// From packages/shared/src/lib/automation/flows/flow-version.ts
export type FlowVersion = {
  connectionIds: string[],  // All connections used
  agentIds: string[]        // All agents used
}
Versions track:
  • Connections: Which connections are used
  • Agents: Which AI agents are referenced
// From packages/server/api/src/app/flows/flow-version/flow-version.service.ts
// Extracted automatically on save:
mutatedFlowVersion.connectionIds = flowStructureUtil.extractConnectionIds(mutatedFlowVersion);
mutatedFlowVersion.agentIds = flowStructureUtil.extractAgentIds(mutatedFlowVersion);

Version Backup and Recovery

Backup Files

// From packages/shared/src/lib/automation/flows/flow-version.ts
export type FlowVersion = {
  backupFiles: Record<string, string> | null  // Map of file IDs
}
Versions can include backup files for:
  • Code action source code
  • Sample data
  • Configuration files

Recovery

If a version is corrupted or lost:
  1. Version History: Access any locked version
  2. Backup Files: Restore from backup file IDs
  3. Export/Import: Export flow and import to new flow

Best Practices

Create locked versions regularly:
  • After significant changes
  • Before testing in production
  • When reaching stable states
  • Before major refactors
This gives you more restore points.
Update the flow display name to reflect major changes:
"User Onboarding v1"
"User Onboarding v2 - Added welcome email"
"User Onboarding v3 - Fixed error handling"
Always test your draft before publishing:
  • Run test flows
  • Verify all steps
  • Check data mappings
  • Review error handling
Use flow notes to document what changed:
{
  "notes": [
    {
      "content": "Added retry logic to API calls",
      "created": "2024-03-15T10:30:00Z"
    }
  ]
}
  • Don’t publish incomplete work
  • Combine related changes into one publish
  • Use draft for experimentation
  • Only publish tested, working versions
Before making risky changes:
  1. Note current published version ID
  2. Make changes in draft
  3. Test thoroughly
  4. Publish
  5. Monitor closely
  6. Rollback if needed

Version Limits

Activepieces keeps all flow versions indefinitely. There’s no automatic cleanup or version limit.
This means:
  • ✅ Complete audit trail
  • ✅ Can rollback to any version
  • ✅ No data loss
  • ⚠️ Storage grows over time (minimal impact)

Troubleshooting

Problem: Old version not showing in history.Solutions:
  • Check pagination - versions may be on next page
  • Verify flow ID is correct
  • Ensure you have permission to view history
Problem: Error when copying version to draft.Solutions:
  • Ensure you have write permissions
  • Check if version exists
  • Verify flow is not locked by another user
Problem: Old version marked as invalid.Reasons:
  • Was published in invalid state (shouldn’t happen)
  • Schema migration issue
  • Piece version no longer available
Solutions:
  • View the version to see validation errors
  • Use as draft and fix issues
  • Contact support if migration issue
Problem: Published version but flow not executing.Check:
  • Is flow enabled? (Toggle must be on)
  • Check operationStatus - might still be enabling
  • Verify trigger configuration
  • Review trigger logs for errors

Next Steps

Publishing

Learn about publishing workflows

Debugging

Debug version issues

Templates

Create reusable templates

Best Practices

Workflow best practices