Migration From Camunda 8
Guía técnica completa para migrar desde Camunda 8 al MVP. Cubre: schema mapping (Postgres ↔ ES/RocksDB), BPMN element conversion table (40+ types mapped, supported/unsupported), variable migration, FEEL→CEL conversion, deployment workflow, process instance state migration, tooling needed (mvp-migrate CLI), phased migration strategy (parallel running → cutover → decommission), rollback plan. Realistic effort: ~2-3 weeks por org tier (small/medium/large).
Audience¶
Esta guía es para teams que actualmente operan Camunda 8 (SaaS o Self-Managed) y consideran migrar al MVP. NO es marketing — es technical reality assessment.
Spoiler: migration es feasible pero non-trivial. Camunda 8 features that MVP no soporta requieren BPMN rework. Plan para 2-3 weeks de migration trabajo per process complejo, dependiendo de feature usage.
Compatibility matrix overview¶
| Category | Compatibility | Notes |
|---|---|---|
| BPMN core elements | 80-90% | Service/User tasks, gateways, events, sub-processes work |
| DMN decision tables | 0% (Phase 1) | Use external decision engine or convert to gateway logic |
| FEEL expressions | 60-80% via conversion | CEL via conversion tool (per ADR-022) |
| Forms | 30% | JSON Schema vs Camunda forms — manual conversion |
| Connectors | 0% (Phase 1) | Rewrite as workers using SDK |
| Process modification | 0% | Out of scope MVP |
| Process migration | 0% | Out of scope MVP (manual) |
| Multi-tenancy | 100% | Mapped |
| Identity (OIDC) | 100% | Standard |
| Authorization | Partial | 3 roles vs 20 resource types — semantic remapping |
| Webhooks (inbound) | 0% | Write own webhook handlers |
| Job workers | 100% | Same pattern (gRPC → REST conversion) |
BPMN element conversion¶
Fully supported (drop-in)¶
| Camunda 8 element | MVP support | Notes |
|---|---|---|
bpmn:startEvent (none) |
✅ Full | |
bpmn:startEvent (message) |
✅ Full | |
bpmn:startEvent (timer) |
✅ Full | Timer durations/cycles supported |
bpmn:startEvent (signal) |
✅ Full | |
bpmn:endEvent (none) |
✅ Full | |
bpmn:endEvent (terminate) |
✅ Full | |
bpmn:endEvent (error) |
✅ Full | |
bpmn:serviceTask |
✅ Full | Same job worker pattern |
bpmn:userTask |
✅ Full | Forms via JSON Schema |
bpmn:sendTask |
✅ Full | Equivalent to serviceTask |
bpmn:receiveTask |
✅ Full | Maps to message intermediate catch |
bpmn:scriptTask |
✅ Limited | CEL expressions only |
bpmn:exclusiveGateway |
✅ Full | CEL conditions |
bpmn:parallelGateway |
✅ Full | Fork + join |
bpmn:eventBasedGateway |
✅ Full | |
bpmn:intermediateCatchEvent (message) |
✅ Full | Message correlation |
bpmn:intermediateCatchEvent (timer) |
✅ Full | |
bpmn:intermediateCatchEvent (signal) |
✅ Full | |
bpmn:intermediateThrowEvent (message) |
✅ Full | |
bpmn:intermediateThrowEvent (signal) |
✅ Full | |
bpmn:boundaryEvent (timer) |
✅ Full | |
bpmn:boundaryEvent (message) |
✅ Full | |
bpmn:boundaryEvent (error) |
✅ Full | |
bpmn:subProcess (embedded) |
✅ Full | Scope handling correct |
bpmn:callActivity |
✅ Full | Input/output mappings |
bpmn:multiInstanceLoopCharacteristics (parallel) |
✅ Full | |
bpmn:eventSubProcess (interrupting) |
✅ Full |
Partial / requires conversion¶
| Camunda 8 element | MVP Phase 1 | Conversion strategy |
|---|---|---|
bpmn:businessRuleTask (DMN) |
❌ → Manual | Convert decision table to exclusive gateway + CEL, or call external decision service |
bpmn:multiInstanceLoopCharacteristics (sequential) |
❌ Phase 2 | Convert to sub-process called N times in loop |
bpmn:inclusiveGateway |
❌ → Manual | Convert to multiple exclusive gateways |
bpmn:complexGateway |
❌ → Manual | Restructure with explicit gateways |
bpmn:boundaryEvent (escalation) |
❌ Phase 2 | Convert to error event |
bpmn:boundaryEvent (compensation) |
❌ → Manual | Implement saga pattern manually in workers |
bpmn:boundaryEvent (conditional) |
❌ Phase 2 | Convert to message-based pattern |
bpmn:eventSubProcess (non-interrupting) |
❌ → Manual | Restructure |
bpmn:adHocSubProcess |
❌ Phase 2 | Restructure as multi-instance or explicit flow |
bpmn:transaction |
❌ → Manual | Use saga pattern |
Not supported (rework required)¶
| Camunda 8 feature | Strategy |
|---|---|
Camunda-specific extensions (zeebe:*) |
Rewrite using MVP extensions |
Camunda forms (zeebe:formDefinition con formId desde Camunda) |
Convert to JSON Schema |
Camunda connectors (zeebe:taskDefinition con type de connector) |
Rewrite as worker |
| Process modification API | Not available — cancel + recreate |
| Process migration API | Not available — let v1 finish, start v2 |
FEEL → CEL conversion¶
Per ADR-022, MVP uses CEL. FEEL expressions need conversion.
Auto-conversion (mvp-cli tool)¶
mvp-cli bpmn convert --from=camunda --to=mvp \
--feel-engine=cel \
process.bpmn
# Output: process.bpmn.converted with CEL expressions
# Output: process.bpmn.report.txt with conversion notes
Conversion patterns¶
| FEEL | CEL |
|---|---|
=amount > 100 |
amount > 100 |
=customer.email |
customer.email |
=count(items) |
items.size() |
=upper case(name) |
name.upperAscii() |
=substring(name, 1, 5) |
name.substring(0, 5) (note: 0-indexed) |
=date and time("2025-01-01T00:00:00") |
timestamp("2025-01-01T00:00:00Z") |
=duration("PT1H") |
duration("1h") |
=customer.tier = "premium" |
customer.tier == "premium" |
=items[item.price > 100] |
items.filter(i, i.price > 100) |
=sum(items.price) |
items.map(i, i.price).sum() |
=if score > 80 then "A" else "B" |
score > 80 ? "A" : "B" |
=every i in items satisfies i.valid |
items.all(i, i.valid) |
=some i in items satisfies i.invalid |
items.exists(i, i.invalid) |
NOT auto-convertible (manual)¶
- DMN-specific FEEL constructs (boxed expressions)
- Custom FEEL functions (no equivalent en CEL)
- Some date/time complex (different APIs)
- FEEL boxed lists with custom evaluation
Manual review needed. Tool flags these explicitly.
Schema mapping¶
Camunda 8 (Elasticsearch indices) → MVP (Postgres tables)¶
| Camunda 8 ES index | MVP Postgres table | Notes |
|---|---|---|
operate-list-view |
process_instances + element_instances joined |
Camunda denormalizes via join relation |
tasklist-task |
user_tasks |
Direct mapping |
operate-incident |
incidents |
Direct mapping |
operate-variable |
variables |
Direct mapping |
zeebe-record-process-instance |
Reconstruct from event_log |
Camunda raw record stream |
operate-flow-node-instance |
element_instances |
Same concept |
operate-decision-instance |
N/A Phase 1 | DMN out of scope |
tasklist-form |
forms |
Schema conversion needed |
operate-batch-operation |
batch_operations |
Same concept |
operate-process-definition |
process_definitions |
BPMN XML stored |
Field mapping example¶
Camunda 8 ListViewTemplate (process instance):
{
"key": 2251799813685250,
"processDefinitionKey": 2251799813685249,
"bpmnProcessId": "order-approval",
"processName": "Order Approval",
"processVersion": 3,
"startDate": "2025-05-01T10:00:00.000Z",
"endDate": null,
"state": "ACTIVE",
"parentProcessInstanceKey": null,
"treePath": "PI_2251799813685250",
"incident": false,
"tenantId": "<default>",
"businessId": "ORD-789"
}
MVP Postgres:
INSERT INTO process_instances (
process_instance_key, -- 2251799813685250
process_definition_key, -- 2251799813685249
bpmn_process_id, -- 'order-approval'
process_definition_version, -- 3
start_date, -- '2025-05-01T10:00:00Z'
end_date, -- NULL
state, -- 'ACTIVE'
parent_process_instance_key, -- NULL
has_incident, -- FALSE
tenant_id, -- '<default>'
business_id -- 'ORD-789'
) VALUES (...);
Straightforward field-to-column mapping. Some fields renamed (camelCase → snake_case).
Migration tooling: mvp-migrate¶
Conceptual tool spec:
# 1. Discover Camunda 8 environment
mvp-migrate discover --camunda-url=https://my.camunda.io \
--client-id=$CID \
--client-secret=$CSECRET \
--output=discovery.json
# Lists: processes, instances, tasks, deployments, etc.
# 2. Plan migration
mvp-migrate plan --discovery=discovery.json \
--output=migration-plan.yaml
# Output:
# - BPMN files identified
# - Compatibility analysis
# - Manual rework items
# - Estimated effort
# 3. Convert BPMN files
mvp-migrate convert-bpmn --input-dir=./bpmn-files/ \
--output-dir=./mvp-bpmn/
# Conversion report per file
# 4. Migrate state (instances, tasks)
mvp-migrate migrate-state --from-camunda \
--to-mvp=https://mvp.example.com \
--batch-size=100 \
--tenant=acme
# Iterates over active instances:
# - Cancel in Camunda
# - Create in MVP with same business state
# - Map variables
# - Resume from equivalent element
# 5. Validate
mvp-migrate validate --instance-keys-file=migrated.txt
Process instance state migration¶
The hard part: in-flight instances cannot be paused mid-execution easily.
Strategy 1: Drain + cutover (recomendado)¶
T-30 days: Deploy v2 in MVP (parallel)
Some new instances go to MVP
Camunda 8 continues with active instances
T-7 days: Stop creating new instances in Camunda
All new traffic to MVP
T-0: Cancel all remaining Camunda instances
Notify users to recreate if business-critical
Decommission Camunda
Pros: simple, no in-flight migration risk
Cons: some lost work, business disruption
Strategy 2: State migration (complex)¶
# Pseudo-code
async def migrate_instance(camunda_pi):
# 1. Cancel in Camunda
await camunda.cancel_instance(camunda_pi.key)
# 2. Determine current state
current_element = camunda_pi.current_element_id
variables = camunda_pi.variables
# 3. Create new instance in MVP
mvp_pi = await mvp.create_instance(
bpmn_process_id=camunda_pi.bpmn_process_id,
variables=variables,
start_instructions=[{
"elementId": current_element # resume from same point
}]
)
# 4. Recreate user tasks if any
for task in camunda_pi.user_tasks_pending:
# MVP creates task automatically via BPMN
# But assignment needs to be preserved
await mvp.assign_task(
task_key=find_equivalent_task(mvp_pi, task.element_id),
assignee=task.assignee
)
return mvp_pi.key
Limitations: - Cannot perfectly reconstruct mid-execution state (e.g., partial sub-process completion) - Variables timing may differ (different timestamps) - Some BPMN features (compensation history) not migratable
Best for: long-running processes (loans, customer onboarding) where Strategy 1 unacceptable.
Strategy 3: Parallel running (most expensive)¶
Run Camunda 8 + MVP concurrently for 3-6 months
New work goes to MVP
Old instances drain naturally in Camunda
Eventually Camunda has 0 instances → decommission
Pros: zero disruption, zero data risk Cons: double cost during overlap
User & tenant migration¶
Camunda 8 Identity → MVP Identity:
# Tenants
for camunda_tenant in camunda.list_tenants():
await mvp.create_tenant(
tenant_id=camunda_tenant.id,
name=camunda_tenant.name
)
# Users (from Identity IdP)
# Camunda 8 typically uses Keycloak/OIDC
# Same IdP can be used by MVP (per ADR-014)
# No user migration needed if same IdP
# Authorization mapping
# Camunda 8 fine-grained → MVP 3 roles
mapping = {
'TENANT_OWNER': 'admin',
'PROCESS_DEFINITION_DELETE': 'admin',
'PROCESS_INSTANCE_CANCEL': 'operator',
'PROCESS_INSTANCE_READ': 'operator',
'JOB_COMPLETE': 'worker',
# ...
}
for user_role in camunda.list_user_roles():
role = highest_permission(user_role.permissions, mapping)
await mvp.assign_role(
user_id=user_role.user_id,
tenant_id=user_role.tenant_id,
role=role
)
Worker migration¶
Camunda 8 workers use gRPC. MVP uses REST.
Conversion pattern¶
// Before (Camunda 8 worker - Java)
@JobWorker(type = "send-email")
public void sendEmail(@Variable Map<String, Object> vars) {
// ...
}
// After (MVP worker - same logic, different SDK)
import { JobWorker } from '@mvp/sdk';
const worker = new JobWorker({
client: mvpClient,
jobType: 'send-email',
handler: async (job) => {
// Same business logic
}
});
Connection string change:
- ZEEBE_CLIENT_BROKER_GATEWAY_ADDRESS=zeebe.camunda.io:443
- ZEEBE_CLIENT_ID=...
- ZEEBE_CLIENT_SECRET=...
+ MVP_ENDPOINT=https://mvp.example.com
+ MVP_API_KEY=...
Variables, headers, retries — semantically same. 80% of worker code unchanged.
Form migration¶
Camunda forms (JSON, custom schema):
{
"type": "default",
"components": [
{
"type": "textfield",
"key": "customerName",
"label": "Customer Name"
},
{
"type": "number",
"key": "amount",
"label": "Amount"
}
]
}
MVP forms (JSON Schema, per ADR-012):
{
"schema": {
"type": "object",
"properties": {
"customerName": { "type": "string", "title": "Customer Name" },
"amount": { "type": "number", "title": "Amount" }
},
"required": ["customerName", "amount"]
},
"ui_schema": {
"customerName": { "ui:widget": "text" }
}
}
Conversion is mechanical. Tool can automate most:
Complex forms (custom widgets, validations) may need manual review.
Migration effort estimate¶
For typical organization:
Small (1-5 processes, < 1000 instances/day)¶
- Discovery + plan: 1 day
- BPMN conversion (tool + manual review): 2-3 days
- Worker migration: 2-3 days
- Form conversion: 1 day
- State migration (strategy 1 or 3): 1-2 weeks
- Testing + validation: 3-5 days
Total: 2-3 weeks
Medium (10-50 processes, 10K-100K instances/day)¶
- Discovery + plan: 1 week
- BPMN conversion (more complex flows): 2-3 weeks
- Worker migration: 2-4 weeks (more workers)
- Form conversion: 1 week
- State migration: 2-4 weeks (more instances)
- Testing + validation: 2 weeks
- Stakeholder training: 1 week
Total: 2-3 months
Large (100+ processes, > 1M instances/day)¶
- Multi-quarter project
- Dedicated team (3-5 engineers)
- Phased per-process migration
- Significant DMN migration work
- Custom tooling extensions
Total: 3-6 months
Rollback plan¶
If migration fails or issues emerge:
During phased migration (Strategy 1 or 3)¶
1. Stop sending new traffic to MVP
2. Re-enable creating instances in Camunda 8
3. Migrate any MVP instances back (reverse direction)
4. Investigate failure cause
5. Plan re-migration
Camunda 8 not decommissioned until migration complete.
After cutover¶
1. Restore Camunda 8 from backup (pre-migration snapshot)
2. Restore data from migration backup
3. Re-route traffic to Camunda
4. Validate
Required: maintain Camunda 8 + backups for at least 30 days post-migration.
Risk mitigation checklist¶
- Inventory of all processes (BPMN + usage frequency)
- Compatibility report run (see #Compatibility matrix overview)
- Manual rework items identified + estimated
- Form library cataloged
- Worker code review for SDK compatibility
- Test environment with MVP running (mirror of Camunda)
- Pilot migration of 1-2 non-critical processes
- Stakeholder sign-off on UX changes (Tasklist different)
- Rollback plan documented + tested
- Communication plan to end users
- Camunda support contract maintained during migration period
Features that prevent migration¶
If your org heavily uses these, migration is not viable (yet):
- DMN decision tables — MVP Phase 1 doesn't support. Plan: external decision engine or Phase 2.
- Process modification API — Used heavily? Stay on Camunda.
- Optimize (process mining) — MVP doesn't replace. Use Grafana + SQL or stay.
- Camunda forms with custom widgets — Significant rework.
- Camunda Connectors ecosystem heavy — Rewrite all as workers.
Don't migrate if these block. Wait for MVP feature expansion or use hybrid.
Decision framework¶
flowchart TD
Start[Should we migrate?]
Start --> SaaS{Camunda 8 SaaS?}
SaaS -->|Yes| TCO[Calculate TCO + real-time advantage]
SaaS -->|No| DMN
TCO --> DMN
DMN{Heavy DMN usage?}
DMN -->|Yes| StopDMN[Don't migrate Phase 1]
DMN -->|No| Opt
Opt{Use Optimize for analytics?}
Opt -->|Yes| GrafanaPlan[Plan Grafana migration]
Opt -->|No| Mod
GrafanaPlan --> Mod
Mod{Process modification workflows?}
Mod -->|Yes| StopMod[Don't migrate - MVP doesn't support]
Mod -->|No| Lang
Lang{Workers in supported languages?}
Lang -->|Java/Python/TS/Go| SDKReady[SDK available, easy migration]
Lang -->|Other| WaitSDK[Wait for SDK or build via OpenAPI]
SDKReady --> Team
WaitSDK --> Team
Team{Team willing 2-3 month project?}
Team -->|Yes| Proceed[Proceed]
Team -->|No| StopTeam[Defer]
Migration timeline template¶
Week 1-2: Discovery + planning
Week 3-4: BPMN conversion + worker code review
Week 5-6: Pilot migration (1 non-critical process)
Week 7-8: Pilot validation + lessons learned
Week 9-12: Phased migration of remaining processes
Week 13: Cutover (Strategy 1) or continued drain (Strategy 3)
Week 14-16: Post-migration monitoring + optimization
Week 17+: Decommission Camunda 8 (if Strategy 1)
Links¶
- analysis/feel-expressions-strategy — FEEL → CEL conversion details
- analysis/webapps-architecture-mvp — UI differences
- adrs/adr-022-cel-for-expressions — Expression engine decision
- adrs/adr-012-json-schema-forms — Forms approach
- analysis/cost-modeling-tco — Cost comparison detail