
Announcements
Hi everyone,
I’ve been spending a significant amount of time working with low-code automated plugins (Power FX plugins) in Dataverse, and I wanted to start a broader discussion around rules, limitations, and practical usage patterns—as well as get feedback from others who have worked with them at scale.
I’ll be candid: I find them simultaneously powerful and frustrating.
On one hand, the ability to execute server-side, transactional logic without writing C# is a huge step forward. Being able to validate, block saves, and perform multi-record updates within a transaction has been a game changer for some of my solutions.
On the other hand, I’ve struggled with:
Sparse or fragmented documentation
Subtle execution-stage differences that are easy to misinterpret
Silent failures or unexpected behavior when patterns are slightly off
Because of that, I started documenting my own findings as I worked through real scenarios (Create, Update, Delete; PreOp vs PostOp; rollups, validations, and change detection). I’m sharing these below not as authoritative guidance, but as working observations that I’m hoping the community can either validate, correct, or expand upon.
Are these rules consistent with what others have observed in production?
Are there recommended patterns Microsoft hasn’t fully documented yet?
Are there “hard rules” vs. “works today but not guaranteed” behaviors?
How are others structuring larger solutions when plugin logic grows beyond a single operation?
Plugins are server-side only (no client APIs)
There is a ~10,000 character limit
No global variables — With() blocks are the only option
Cannot assign to multiple Events/Stages (One Event + Stage per Plugin)
Cannot set operation order - Plugins triggered on same Event + Stage (At least in Accelerator App)
Dataverse Accelerator App Extremely Buggy
Logic must be deterministic and transactional
| Event / Stage | Record Exists? | Typical Use |
|---|---|---|
| Create – PreOp | ❌ No | Validation, defaults |
| Create – PostOp | ✅ Yes | Rollups, related updates |
| Update – PreOp | ✅ Yes | Validation, field updates |
| Update – PostOp | ✅ Yes | Related updates only |
| Delete – PreOp | ✅ Yes | Validation, cleanup |
| Delete – PostOp | ❌ No | (Not Found One Yet) |
Some of these took longer than I’d like to admit to diagnose:
Using ThisRecord outside of within a ForAll()
Self-referencing variables inside With()
Comparing lookup objects instead of their primary keys
Registering multiple plugins on the same event/stage (execution order is unpredictable)
Attempting change detection (OldRecord.Field <> NewRecord.Field) in PostOp
Using Set() for lookup fields (requires Patch() instead)
Validation (PreOp):
Use Error() to block saves
Keep logic simple and explicit
Change Detection (Update PreOp):
Compare OldRecord vs NewRecord
Navigate lookup comparisons via primary keys
Rollups (PostOp):
Always calculate using persisted data
Only update related records, never the triggering one
Delete Adjustments (PreOp):
Perform cleanup or rollbacks while the record still exists
| Function | Best Use |
|---|---|
Set() |
Triggering record only, PreOp |
Patch() |
Any record, required for lookups |
With() |
Block-scoped variables (no self-reference) |
Collect() |
Works, returns a record (not a table) |
Error() |
Validation & transaction stop |
Are there unsupported but currently working patterns we should avoid?
Is there any roadmap for improved debugging or authoring experience?
How are others handling complex orchestration without reverting to C# plugins?
Are others converting Power Automate Flows to these automated plugins?
I’m very open to correction here—if something I’ve listed is inaccurate or context-dependent, I’d genuinely appreciate the clarification. My goal is to better understand how to use these plugins confidently and predictably, not to criticize the feature.
Thanks in advance to anyone willing to share their experience.