A definition is a rule carrying exactly one effect. An initiative is a set of them with a parameter surface of its own. An assignment binds either to a scope and starts the engine. Most of the trouble estates have with this product traces back to those three sentences.
Three objects, and one effect each
A policy definition is a JSON document holding a rule and a single effect. That constraint shapes everything downstream, so it is worth sitting with. You cannot write one definition that audits in development and denies in production. You write the definition once and control the severity at assignment time through a parameter, which is why nearly every built-in you read exposes an effect parameter with an allowedValues list. The definition carries the logic. The severity is a decision made later, by whoever assigns it, and that separation is the single most useful property of the object model.
An initiative, which the SDKs and the ARM API still call a policy set, is a collection of definitions with its own parameters. Those parameters feed the member definitions, so an initiative containing one policy that expects an array of locations and another that expects a single location can expose both. It can also expose a fixed list of permitted values that the assigner has to choose from, and that option deserves a moment of thought before you use it. Once an initiative defines the allowed values for a parameter, no assignment can supply anything outside the list. You have moved a decision from the assigner to the author, and undoing it means editing the initiative rather than the assignment.
An assignment binds a definition or an initiative to a management group, subscription, resource group or single resource, supplies the parameter values, and starts evaluation. It is the only one of the three objects that does anything.
Assign initiatives, even when you have one rule
Microsoft’s own recommendation is to create and assign an initiative even when it holds a single definition, and I follow it without exception. The reasoning is arithmetic. Adding a definition to an initiative that is already assigned makes the new rule live at every scope that initiative reaches, with no new assignment created and no scope touched. Adding a definition that was assigned on its own means a fresh assignment at every scope where you want it, and each of those is another object to name, parameterise, monitor and eventually remember to delete. Estates that assign definitions directly accumulate hundreds of assignments and lose the ability to reason about any of them.
There is one documented exception and it is worth respecting. Evaluating an initiative assignment evaluates everything inside it. If a rule has to be measurable on its own, in isolation from the rest of a control set, keep it out of the initiative and assign it directly.
Inheritance that only ever subtracts
Assignments flow downward and everything beneath a scope inherits. The direction is absolute in a way that catches people out. You can exclude a subscope from an assignment. You cannot override that assignment from below.
The pattern I see attempted most often is an allowed-resource-types assignment at a management group, followed by a more permissive assignment on a child management group so that one team can use something the parent forbids. It does not work and it cannot, because Azure Policy is an explicit deny system. No rule anywhere grants permission. Rules only ever take capability away, so when two assignments disagree the more restrictive one decides, and the only route to letting that team have their resource type is to exclude their scope from the parent assignment and assign the permissive version there instead.
Nothing in Azure Policy grants. Rules only take away, so the only way to permit something is to stop forbidding it somewhere higher.
Read as a design rule rather than a quirk, this decides the shape of a management group hierarchy more than any other single fact about the product. Rules go high, exceptions travel through exclusions and exemptions, and the moment you find yourself wanting to hand capability back at a lower scope, you have learned that the assignment above it is sitting one level too high. That is a cheap correction on the day you notice it and an expensive one two years later, when four teams have built around the exclusion you added instead.
The assignment holds a reference, not a copy
An assignment points at a definition. It does not snapshot it. When the definition changes, every assignment of it changes behaviour at the next evaluation, with no action from whoever owns those assignments and no notification to them. For your own custom definitions that is exactly the behaviour you want, and it is also how one careless edit reaches every scope in the tenant at once. For built-ins it means Microsoft can change the logic underneath your assignments, which they do, on a versioning scheme you can opt into.
An assignment can pin a version of a built-in rather than following the latest, and the pinning has limits worth knowing before you build a process on it. You can hold a major version and float everything beneath it, or hold major and minor and float the patch. You cannot pin an exact patch, by design, because patch-level changes are always taken automatically. Initiatives are versioned on the same scheme. The feature’s status is genuinely muddled as at August 2026: stable ARM API versions accept the field, the portal labels it as preview, and at least one concept page still describes the capability in the future tense. The rollout article deals with how to use versions during a change. The point to take from here is narrower, which is that an unpinned assignment is a standing agreement to accept an author’s future edits, and for built-ins that author is not you.
Define high, assign lower
Definitions and assignments do not have to live at the same scope and they should not. Create definitions high, usually at the intermediate root management group, and assign them beneath. A definition held at a management group can be assigned anywhere below it. A definition created on a subscription can only ever be assigned inside that subscription, so the day a neighbouring team needs the same rule they will copy it rather than reference it, and from that morning you have two definitions that were once identical and will not stay that way.
Most of the custom definition sprawl I am asked to clean up began as three teams solving the same problem in three subscriptions, each unaware of the others. The cleanup is not technically hard. It is politically slow, because by the time anyone notices, each of those definitions has an assignment somebody depends on and a parameter value somebody chose.
What the engine does not look at
Everything under the Microsoft.Resources provider is exempt from evaluation by design, with subscriptions and resource groups as the deliberate exceptions. That is a small piece of trivia until you try to write a rule about deployments themselves and cannot understand why it never fires.
The sharper omission concerns rules that inspect who is making a request rather than what is being made. Policy can now read the identity context of a request and enforce on it, and those rules act at request time only. The compliance engine marks them NotApplicable rather than compliant or non-compliant, so an identity-aware rule doing its job perfectly will never show up as a green line on a compliance report. Anyone who has promised a dashboard covering every control needs to know that before they promise it. The effects article takes that surface apart properly, including how much of it is still moving.
Whose definition is it
One more property before you go anywhere near a rule. Every definition carries a policyType that you cannot set and that decides who maintains it. BuiltIn is Microsoft’s, maintained by Microsoft, versioned by Microsoft. Custom is yours, maintained by nobody unless you name somebody. Static is a stranger case belonging to the regulatory initiatives, and it is covered later.
That single property is the axis the middle of this series runs along. A built-in you assign is somebody else’s ongoing commitment. A built-in you copy stops being that the moment you copy it, and there is no edit path that keeps the connection, because there is no edit path at all. Knowing which type you are looking at, and what changing it would actually mean, is worth more day to day than any amount of fluency in the rule language.
From here
With the object model in hand, the next article goes to the catalogue, because the productive first move in Azure Policy is almost never writing a rule. It is finding the one that already exists, reading it properly, and knowing what assigning it commits you to.
Azure Policy
‹ Previous: [AP 1] Azure Policy: Where Intent Becomes Enforcement
Next: [AP 3] What Microsoft Already Ships: Reading the Catalogue ›




