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.
What I’m Hoping to Learn from the Community
-
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?
My Current Understanding & Findings
1. Execution Limits & Environment Rules
-
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
2. Record Existence by Event & Stage
| 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) |
3. Common Mistakes I’ve Personally Hit
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)
4. Patterns That Have Worked Reliably
Validation (PreOp):
Change Detection (Update PreOp):
Rollups (PostOp):
Delete Adjustments (PreOp):
5. Function Usage Rules (Observed)
| 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 |
6. Open Questions
-
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.