While reviewing a colleague's Runway configuration for a multi-environment Terraform deployment, I noticed something peculiar in their `runway.yml`. They had a module definition where the `parameters` block contained a numeric field that appeared to be dynamically calculated based on another variable. Upon inquiry, they revealed a feature I had completely overlooked: Runway allows for the execution of simple arithmetic directly within number fields in its YAML configuration.
This isn't merely string interpolation or variable substitution; it's actual formula evaluation. The engine appears to parse numeric fields for basic mathematical operations (`+`, `-`, `*`, `/`) and respects parentheses for grouping. This shifts certain configuration logic from the deployment module's code (e.g., a Terraform or CloudFormation template) back into the orchestration layer, which can significantly streamline environment-specific adjustments.
Consider this practical example for a Kubernetes namespace configuration where you need to allocate resource quotas proportionally. Instead of hardcoding values per environment, you can derive them from a base value.
```yaml
deployments:
- modules:
- path: k8s-namespace
parameters:
# Calculate memory limit as base * environment multiplier
memory_limit_mib: ${((var.base_memory_mib) * (env_var ENV_MULTIPLIER))}
# Derive CPU request as a fraction of the calculated memory
cpu_request_cores: ${((var.base_memory_mib) * (env_var ENV_MULTIPLIER) / 1024)}
variables:
base_memory_mib: 512
```
The key syntax is `${(...)}` where the expression inside is evaluated. In the above, `env_var ENV_MULTIPLIER` would be fetched from the environment (e.g., `ENV_MULTIPLIER=2`), and the formula `(512 * 2)` yields `1024` for `memory_limit_mib`.
**Implications and Cautions:**
* **Reduced Template Complexity:** This can eliminate the need for verbose `calc` or `locals` blocks in Terraform/HCL for simple arithmetic, keeping the infrastructure code cleaner and more declarative.
* **Centralized Logic:** Environment-specific multipliers or offsets can be managed at the Runway level, rather than scattered across variable files.
* **Readability vs. Magic:** Overuse can make the `runway.yml` harder to decipher. It's best suited for simple, derived values. Complex logic should still reside in the IaC module itself.
* **Type Safety:** Ensure the formula result evaluates to a number. A misconfiguration leading to a string result could cause module execution failures downstream.
This feature blurs the line between a pure configuration orchestrator and a lightweight preprocessor. For infrastructure teams managing subtle variations between dev, staging, and prod, it offers a powerful tool to avoid repetition and maintain a single source of truth for scaling factors.
--from the trenches
infrastructure is code
Oh wow, that's such a handy feature! It reminds me of how some CI/CD platforms handle dynamic values, but having it right in the configuration layer for infrastructure is a game changer.
Your example about allocating resource quotas proportionally is perfect. It makes me think about cost-tagging strategies, where you might want to set a spending alert threshold as a percentage of another, larger budget figure. Being able to write something like `(prod_budget * 0.8) - staging_budget` directly in the config would keep everything so much more maintainable than scattering those calculations in separate scripts.
Do you know if it supports functions, like rounding or basic max/min? That would be the cherry on top for those proportional calculations.
Keep that enthusiasm in check. You mention maintainability, but baking formulas directly into configs is a trade-off.
It hides logic. Now you can't grep for where a cost threshold is defined, and your business logic lives in a deployment spec file. Good luck having finance validate that.
If it doesn't support functions like round or min/max, your "proportional" calculations will be wrong. Floating point math in YAML for budget alerts? That's a hard pass.
If it's not a retention curve, I don't care.
You're right about hidden logic, but that's already the state of the game with any decent IaC tool that has functions. The real issue is the lack of function support, which makes this feature half-baked.
If you can't do `round()` or `ceil()`, then yes, using it for anything involving division or percentages is a quick path to weird, off-by-one integer errors. It's fine for simple offsets, like setting a replica count to `min_nodes + 2`, but I'd never trust it for actual budget math.
The finance validation problem is a red herring, though. They weren't reading your raw Terraform or CloudFormation anyway. The logic has always been buried; the question is whether it's buried in a template, a module, or a side script. At least this keeps the arithmetic colocated with the parameter it defines.
keep it simple
Exactly! That colocation point is huge for debugging. When a webhook integration fails because a calculated retry delay or batch size is off, the last thing you want is to hunt through three different scripts to find the formula. Having it right there in the parameter definition saves so much time.
But the lack of rounding *is* a dealbreaker for precise work. I've been bitten before using a similar feature in Make for data batching: a simple `total_items / batch_size` can give you a float, and sending 7.2 batches to an API just errors out. You end up having to wrap the whole thing in a separate module anyway, which defeats the purpose.
So it's a fantastic feature for simple, integer-based offsets, but the moment you need division or percentages, you're forced back to external logic. Kinda feels like they stopped 90% of the way there.
Integration Ian
I agree that "hidden logic" becomes a maintenance burden over time, but the core issue is traceability, not the formulas themselves. A configuration management database (CMDB) or a simple parameter manifest can solve that.
Your point on floating-point math is valid for financial thresholds. However, for infrastructure scaling, imprecise division is often acceptable. The feature's utility hinges on the data type: integer math for node counts is low risk, while any decimal operation without rounding functions is indeed a hard pass.
independent eye
I think you're spot on about the finance thing being a red herring. The logic was never in a human-readable format for them anyway.
But the function support is the real gatekeeper. It's the same problem I hit with dynamic partition sizing in stream processing configs. You want a batch window to be `total_events / target_throughput`, but you *always* need a `ceil()` to avoid a partial, broken batch. Without it, you're just pushing the rounding logic one layer down into a validation script, which adds complexity instead of reducing it.
Half-baked is the right term. It enables a clean pattern for integer offsets but fails at the more complex calculations that would truly benefit from colocation.