What you will be able to do
- Use built-in substitutions such as ${bundle.target} to give each target its own paths and names
- Declare custom variables and reference them with ${var.<name>}
- Set a variable's value with --var, BUNDLE_VAR_ environment variables, variable-overrides.json, or a target's variables mapping, and predict which value wins
- Use complex and lookup variables, and check resolved values with databricks bundle validate --output json
Key concept
Deployment-time variable resolution — A bundle keeps one set of configuration files, and the values that differ between environments are filled in when you deploy to a target. The values that are resolved at deploy time are baked into the deployed job or pipeline. Values passed later, when the job runs, do not change them.
1.Substitutions: values the bundle already knows
When you promote the same codebase from dev to test to prod, most of the configuration stays the same. What changes is where it is deployed, what it is named, and which compute it uses. Declarative Automation Bundles (formerly Databricks Asset Bundles) handle this with two features: substitutions and custom variables. Both let settings be determined at the time a bundle is deployed and run, not hard-coded.
Substitutions read values the bundle already has, such as its name, the target being deployed, or the current user. The most important one for environment-specific configuration is ${bundle.target}. It resolves to the name of the target you deploy to, so one line of YAML gives each environment its own path.
bundle:
name: hello-bundle
workspace:
root_path: /Workspace/Users/${workspace.current_user.userName}/.bundle/${bundle.name}/my-envs/${bundle.target}
targets:
dev:
default: trueIf someone@example.com deploys this, the root path becomes /Workspace/Users/someone@example.com/.bundle/hello-bundle/my-envs/dev. Substitutions can also point at fields of other resources in the same bundle, using forms like ${resources.jobs.<job-name>.id} or ${resources.pipelines.<pipeline-name>.name}.
Checkpoint 1 of 5· Check yourself
An older bundle example builds a path with ${bundle.environment}. Which substitution do the current docs say to use instead?
${bundle.target} resolves to the name of the target being deployed and replaces the older ${bundle.environment}.
“${bundle.target} # Use this substitution instead of ${bundle.environment}”Source: docs.databricks.com
2.Custom variables: values you choose
Substitutions only cover values the bundle already knows. For anything else, such as a cluster ID, a notebook path, or a catalog name that differs between environments, you declare a custom variable. You declare custom variables in the top-level variables mapping. Each variable can have a description and a default.
variables:
my_cluster_id:
description: The ID of an existing cluster.
default: 1234-567890-abcde123
my_notebook_path:
description: The path to an existing notebook.
default: ./hello.pyIf a variable has no default, you must supply its value some other way before the bundle commands can use it. The next section covers those ways.
Checkpoint 2 of 5· Fill the gap
Which prefix completes the reference to the custom variable?
resources:
jobs:
hello-job:
name: hello-job
tasks:
- task_key: hello-task
existing_cluster_id: ${ ? .my_cluster_id}
notebook_task:
notebook_path: ${var.my_notebook_path}Custom variables are always referenced with the ${var.<variable_name>} substitution. variables is the name of the mapping where you declare them, not the reference prefix.
Source: docs.databricks.comTiming matters here. Variables are resolved when you deploy. When you run a job, you run the job that was already deployed, with the values from that deployment. Passing a different variable value at run time does not change it. To vary a single run, use job parameters.
Model answer: bundle variables are interpreted when the bundle is deployed. Running a job runs the previously deployed job with the variable values from that deployment, so a different value passed for the run does not apply. To change something for a single run, the teammate should pass the value as a job parameter instead.
Sources1
3.Setting a variable's value, and which value wins
Besides the default, there are four places to give a variable a value. Together they let the same configuration files serve every environment.
| Approach | Form |
|---|---|
| Overrides file | .databricks/bundle/<target>/variable-overrides.json |
| Default | default under the top-level variables mapping |
| Command option | --var="<key>=<value>" on validate, deploy, or run |
| Target mapping | targets: <target>: variables: <name>: <value> |
| Environment variable | Name starts with BUNDLE_VAR_, e.g. BUNDLE_VAR_my_cluster_id |
The targets-mapping approach is the core of environment promotion. Each target gives the same variable its own value, for example one cluster ID for dev and another for prod. The resources that use ${var.my_cluster_id} stay exactly the same. The variable is declared once in the top-level variables mapping, as in the previous section, and each target sets a value using the form below.
variables:
<defined-variable-name>: <non-default-value> # value for this targetThe overrides file is a JSON file at .databricks/bundle/<target>/variable-overrides.json, one per target. It holds variable names and values, and it can hold complex values too. The example below shows a complex variable named my_cluster in that file.
{
"my_cluster": {
"spark_version": "13.2.x-scala2.11",
"node_type_id": "Standard_DS3_v2",
"num_workers": 2
}
}When more than one source sets a value, the CLI checks them in a fixed order and stops at the first value it finds.
Checkpoint 3 of 5· Put it in order
Order the places the Databricks CLI checks for a variable's value, from first checked (highest priority) to last.
- 1.--var options on the bundle command
- 2.The variables mapping inside the targets mapping
- 3.The variable-overrides.json file
- 4.Environment variables beginning with BUNDLE_VAR_
- 5.The default in the top-level variables mapping
The CLI stops at the first value it finds. A --var option therefore beats an environment variable, which beats the overrides file, then the target mapping, then the default.
“Within any --var options specified as part of the bundle command.”Source: docs.databricks.com
Checkpoint 4 of 5· Exam question
A data engineering team maintains a single job definition in an Automation Bundle that must write to a different Unity Catalog catalog depending on whether it is deployed to the `dev` or `prod` target, without duplicating the job's YAML. What should they do?
Correct answer: A — Declare a `catalog` variable with a default value, reference `${var.catalog}` in the job's task config, and override it per target in `databricks.yml`.
- A. Declaring a `catalog` variable with a default and referencing `${var.catalog}` in the task config lets the single job definition stay unchanged while each target block supplies its own catalog value. This is the standard bundle pattern for environment-specific configuration without duplicating resources.
- B. Duplicating the job into two hardcoded resources defeats the purpose of a shared bundle codebase and forces the team to keep two YAML definitions in sync manually. Any future change to the job logic now has to be made twice.
- C. Reading the catalog name from a notebook widget at runtime bypasses bundle configuration entirely and is not how Automation Bundles pass environment-specific values into job tasks. It also makes the value invisible to `bundle validate`.
- D. A workspace-wide Unity Catalog default is a governance setting, not a bundle mechanism, and it cannot differentiate between the `dev` and `prod` targets of the same bundle deployment. It would apply the same catalog everywhere regardless of target.
4.Complex variables, lookups, and checking resolved values
Variables are strings by default. To pass a whole structure, such as a cluster definition that should be larger in prod, set type: complex and give a structured default. You can then use it in a job like new_cluster: ${var.my_cluster}. You can also define complex values in variable-overrides.json.
A lookup variable solves a different problem. Object IDs often differ between workspaces, but names can stay the same. A lookup takes the name of an object and resolves it to that object's ID. Lookups are available for these object types: alert, cluster_policy, cluster, dashboard, instance_pool, job, metastore, notification_destination, pipeline, query, service_principal, and warehouse.
variables:
my_cluster_id:
description: An existing cluster
lookup:
cluster: '12.2 shared'The lookup fails with an error if no object has that name, or if more than one does. Before deploying anywhere, run databricks bundle validate to make sure your substitutions and variables parse. Add --output json to see the values that will actually be used. The output shows each variable's default next to its resolved value.
Checkpoint 5 of 5· Check yourself
A variable uses lookup: cluster: '12.2 shared', but two clusters in the workspace have that exact name. What happens?
A lookup must match exactly one object. An error occurs both when no object has the name and when more than one does.
“or if there is more than one object with the specified name”Source: docs.databricks.com
databricks bundle validate --output json. The resolved job definition shows the substituted existing_cluster_id, and the variables section shows each variable's default and value.
Sources1
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Passing --var to databricks bundle run changes the variable values that the already-deployed job uses.Why is that wrong?
Variables are resolved at deploy time. A run uses the job as it was deployed, so to vary a single run, pass job parameters.
Covered in Custom variables: values you choose
2.A value set in a target's variables mapping overrides a BUNDLE_VAR_ environment variable, because the target is more specific.Why is that wrong?
The CLI checks --var first, then BUNDLE_VAR_ environment variables, then variable-overrides.json, then the targets mapping, and finally the default.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“settings can be determined at the time a bundle is deployed and run”
↩︎ Substitutions: values the bundle already knows“${bundle.target} # Use this substitution instead of ${bundle.environment}”
↩︎ Substitutions: values the bundle already knows“To reference a custom variable within your bundle configuration, use the variable substitution ${var.<variable_name>}.”
↩︎ Custom variables: values you choose“Bundle variables are deployment-time variables. They are interpreted when you deploy the bundle.”
↩︎ Custom variables: values you choose“The environment variable's name must start with BUNDLE_VAR_.”
↩︎ Setting a variable's value, and which value wins“The Databricks CLI looks for values for variables in the following order, stopping when it finds a value for a variable”
↩︎ Setting a variable's value, and which value wins“use the same approach during both the deployment and run stages”
↩︎ Setting a variable's value, and which value wins“You can also define complex variables in the variable-overrides.json file.”
↩︎ Setting a variable's value, and which value wins“A custom variable is assumed to be of type string unless you define it as a complex variable.”
↩︎ Complex variables, lookups, and checking resolved values“the ID of the object with the specified name is used as the value of the variable”
↩︎ Complex variables, lookups, and checking resolved values“To view values that will be used when you deploy a bundle, use the --output json option”
↩︎ Complex variables, lookups, and checking resolved values“Bundle variables are deployment-time variables. They are interpreted when you deploy the bundle.”
↩︎ Key concept“Instead, pass values to a job run using job parameters.”
↩︎ Exam trap 1“Within any environment variables set that begin with BUNDLE_VAR_.”
↩︎ Exam trap 2“${resources.pipelines.my_pipeline.schema} resolves to pipeline_bundle_dev when you deploy to the dev target”
↩︎ Prediction“Within any --var options specified as part of the bundle command.”
↩︎ Checkpoint“or if there is more than one object with the specified name”
↩︎ Checkpoint - 2.
“databricks.yml is the main configuration file that defines a bundle”
↩︎ Substitutions: values the bundle already knows - 3.
“the setting in the targets mapping takes precedence over the setting in the top-level resources mapping”
↩︎ Setting a variable's value, and which value wins