Performance with Constraints¶
Constraints are designed to be deterministic and debuggable, but they still have a cost model. This guide explains what matters in real apps.
See also:
- docs/guide/performance.md
- docs/dev/testing.md (perf and audit gates)
Cost model (what you pay for)¶
- Parsing:
expr("...")parses DSL text into a frozen AST. - Graph build: expressions referencing
parent/viewport/#id/intrinsicparticipate in a dependency graph. - Resolution: expressions are evaluated deterministically against resolved ref values.
- Layout: resolved numbers flow into the layout engine.
Helper constraints compile to expr("..."), so they share the same underlying work.
Implementation note: expr("...") is cached by source string (small LRU), so repeating the same expression source does not re-parse each frame.
Best practices¶
- Prefer helpers: they reduce mistakes and keep expressions simple.
- Hoist stable constraints out of hot render paths when practical:
const showRail = visibilityConstraints.viewportWidthAtLeast(110)
app.view(() => ui.box({ display: showRail }, [...]))
- Avoid generating lots of unique expression strings per frame (for example string concatenation with varying numbers).
- Use
steps(...)or a small number of discrete breakpoints rather than many micro-variants.
When to simplify¶
If you’re using constraints for something that’s naturally expressed by:
- flex
- fixed sizes
- fluid(...)
…switch back to those simpler primitives. Constraints are for relationships, not for everything.
Validation tools¶
- Run the full deterministic test suite:
npm run buildnode scripts/run-tests.mjs- Use frame-audit when changing layout/constraints:
docs/dev/live-pty-debugging.md