ap project replace CLI mirrors a project’s flows, table schemas, and folders from one Activepieces deployment to another using direct API calls. Use it from CI/CD to promote work between independent staging and production instances when Git-based Project Releases aren’t a fit.
Prerequisites
- The Environments feature must be enabled on the destination platform’s plan — see Project Releases prerequisites.
- You need a platform-scoped API key (
SERVICEprincipal) on both instances. The same project id format must be used on each side. - Both deployments must share the same major Activepieces version, and the destination version must be greater than or equal to the source version.
What gets mirrored
Installation
activepieces CLI is shipped with each Activepieces release; pin the version that matches your destination instance to keep request shapes aligned.
Command
Flags
Exit codes
What happens when you run it
- CLI lists the source project’s flows, folders, and table schemas via the source instance’s REST API.
- CLI packages them into a
ProjectReplaceRequestandPOSTs to/v1/projects/:projectId/replaceon the destination. - Destination acquires a per-project
NoWaitlock. If another replace is in flight, it returns409 REPLACE_IN_PROGRESS. - Destination preflight (no writes if any of these fail):
- Activepieces version is parsed; same major +
dest >= source. - For every source connection: if the destination already has one with the same
externalId, itspieceNamemust match.
- Activepieces version is parsed; same major +
- Install phase — for each entry in
requiredPiecesnot already on dest at the exact pinned version, the server installs it from npm (packageType: REGISTRY, scope: platform). All installs are attempted; if any fail, the response aborts with502listing every failure. No other writes have happened at this point — folders, tables, flows, and connections are still untouched. - Apply phase — connections, then folders, then tables, then flows are created/updated. Deletes run in reverse order. Each item runs in its own try/catch; per-item failures are collected, systemic 5xx errors abort the run.
- Audit event
project.replacedis emitted only when the apply phase ran — onSUCCESSorPARTIAL_FAILURE. Rejected attempts (preflight failure, install failure, lock contention) are not audited.
Output
Human-readable (default)
--json
Preflight failures (exit 2)
AP_VERSION_MISMATCH, PIECE_VERSION_MISMATCH, CONNECTION_PIECE_MISMATCH.
Install failures (exit 3, HTTP 502)
Idempotency and retries
Re-running the CLI after a partial failure converges to the source state. Items applied on the previous run are detected as unchanged via a typed deep-equality check and skipped; failed items are retried. The destination is left in a partially-applied state on hard failure — by design, since pause/restore would force downtime on every successful release. The apply phase is not wrapped in a single database transaction, and that’s deliberate:- Partial-success semantics (
207+failed[]) require successfully-applied items to persist across a sibling failure. A single transaction would roll back every successful folder/table/connection just because one flow’s republish failed. - Flow republish dispatches BullMQ jobs and trigger-source registrations that can’t sit inside a SQL transaction.
- Recovery is by re-run, not rollback. Every operation matches by
externalId, so a process crash mid-apply leaves the destination in some intermediate state that the next run’s diff phase detects and finishes. CI/CD’s natural retry handles process-level failures (OOM, SIGKILL, deploy timeout).
0.
Connections
Connection metadata (externalId, pieceName, displayName) is mirrored to the destination as placeholder records withstatus: MISSING. Secret values (OAuth tokens, API keys, etc.) never cross the wire — each instance keeps its own.
After a replace, the CLI prints any connections that still need authorization on the destination:
ACTIVE.
If a connection on the destination already exists with the same externalId but a different pieceName, the replace fails preflight with CONNECTION_PIECE_MISMATCH so the conflict can be resolved without overwriting unrelated flows.
GitHub Actions example
Troubleshooting
409 REPLACE_IN_PROGRESS
409 REPLACE_IN_PROGRESS
Another replace is running against the same destination project. Wait a few seconds and retry — the lock is per-project and released as soon as the previous run finishes.
Install failed (502)
Install failed (502)
The CLI passed preflight but a required piece couldn’t be installed on the destination. Check
failures[*].message in the response — most commonly the piece doesn’t exist on npm at that version, the registry is unreachable, or the engine crashed during metadata extraction. The replace aborted before any writes; fix the install issue and re-run.PIECE_VERSION_MISMATCH
PIECE_VERSION_MISMATCH
The destination already has the piece installed at a different version than the source. Either upgrade/downgrade the destination piece manually, or update the source flow to use a version compatible with what’s on the destination.
CONNECTION_PIECE_MISMATCH
CONNECTION_PIECE_MISMATCH
The destination already has a connection with the same
externalId but for a different piece. Either rename the source’s externalId or delete/replace the conflicting connection on the destination before re-running.AP_VERSION_MISMATCH
AP_VERSION_MISMATCH
The destination is on an older version or a different major than the source. Upgrade the destination first.
Feature is disabled
Feature is disabled
The destination platform’s plan does not have the Environments feature enabled. Contact your platform owner.