Parameterize Databricks Notebooks
Use parameters to parameterize notebooks in Databricks — reduce duplication, run the same notebook for different inputs, and build reusable pipelines.
Focus: use parameters to parameterize notebooks
Use Parameters to Parameterize Notebooks
You've just written a notebook that processes sales data perfectly — for one region, on one date. Then someone asks for the same report for another region. You copy the notebook, change a few hard-coded values, and hope you remember to fix the other three places. This is the pain that parameterization solves: without a way to inject inputs, every variation of your logic becomes a separate, brittle copy that rots over time. In this lesson, you'll learn how to make any Databricks notebook reusable by parameterizing it — so the same code runs for any input, in any environment, with zero copy-paste.
The problem this lesson solves
Hard-coded values are the silent killer of maintainable pipelines. Imagine a notebook that loads a Delta table, filters on 2024-01-01, and writes results to a path like /mnt/reports/sales_2024_01_01. It works — until another team asks for the same logic with a different date. Now you have two notebooks, and the next change requires editing both. Multiply that by ten regions, five date ranges, or three output formats, and you've created a maintenance nightmare.
Parameterization solves this by turning your notebook into a function — a reusable unit that accepts inputs and produces outputs. Instead of writing a new notebook for each variation, you write one notebook that reads its inputs from parameters. This reduces duplication, centralizes logic, and makes your pipelines auditable and testable.
Why care now? In any serious data engineering workflow, you'll soon need to run the same transformation with different inputs — as part of an orchestrated job, from a dashboard, or in a multi-tenant environment. Notebook parameterization is the foundational technique that makes your code reusable and your pipelines reproducible.
Core concept / mental model
Think of a parameterized notebook as a vending machine. The machine has a fixed interior — the logic that processes whatever you put in. You press a button (pass a parameter) to choose what you want. The machine runs the same internal steps, but the output changes based on your choice. In Databricks, widgets are the buttons, and dbutils.widgets.get() is the slot that delivers your input.
Two primary mechanisms exist for parameterization in Databricks:
- Notebook widgets: The built-in UI controls (dropdowns, text boxes) that let users set values interactively and let jobs pass values at runtime.
dbutils.notebook.run(): The way to call another notebook from within a notebook, passing a dictionary of parameters.
Here's a mental diagram:
[Job / Orchestrator] → [Notebook with widgets] → (Logic) → [Output table/path]
| ↑
└─────── parameters ──┘
The notebook reads parameters at the top, uses them throughout, and produces results that depend on those inputs. The logic is the same; only the inputs change.
Pro tip: Treat your parameter names as a contract. If you change a widget name, every caller that passes that parameter will silently fail — use consistent naming like
date_from,region,output_table.
How it works step by step
Here's the flow from creating a widget to using it in your notebook:
- Create a widget using
dbutils.widgets.text(name, default_value, label)— or dropdown, combobox, etc. - Retrieve the value using
dbutils.widgets.get("name")— this returns a string, even if you expect an integer or date. - Type-cast and validate the value (e.g., convert to
int,date, orDecimal). - Use the value in your Spark SQL, DataFrame transformations, or paths — after interpolation.
- Optionally remove widgets after use with
dbutils.widgets.removeAll()to keep the notebook clean when run as a job.
When you run the notebook from a job, the job submits parameters that override the widget defaults. The same notebook can be called with different parameters without any code changes.
Hands-on walkthrough
Let's build a reusable notebook that filters and aggregates data based on parameters.
Example 1: Basic parameterized filter
from pyspark.sql import functions as F
from datetime import datetime
# 1. Create widgets with defaults
dbutils.widgets.text("date_from", "2024-01-01")
dbutils.widgets.text("date_to", "2024-12-31")
dbutils.widgets.text("table_name", "sales")
# 2. Retrieve values (always strings!)
date_from = dbutils.widgets.get("date_from")
date_to = dbutils.widgets.get("date_to")
table_name = dbutils.widgets.get("table_name")
# 3. Convert to proper types
from datetime import datetime
date_from_dt = datetime.strptime(date_from, "%Y-%m-%d")
date_to_dt = datetime.strptime(date_to, "%Y-%m-%d")
# 4. Use the values in a query
filtered_df = spark.sql(f"""
SELECT * FROM {table_name}
WHERE date BETWEEN '{date_from}' AND '{date_to}'
""")
# 5. Show the count as output
print(f"Rows between {date_from} and {date_to}: {filtered_df.count()}")
filtered_df.display()
Expected output (when defaults are used):
Rows between 2024-01-01 and 2024-12-31: 12345
Example 2: Using dbutils.notebook.run() to call a parameterized notebook
Often you'll orchestrate multiple notebooks. Here's how one notebook can call another, passing parameters.
child_notebook (a parameterized notebook):
dbutils.widgets.text("region", "all")
dbutils.widgets.text("date", "2024-01-01")
region = dbutils.widgets.get("region")
date = dbutils.widgets.get("date")
print(f"Processing data for region={region} on date={date}")
# ... transformation logic ...
parent_notebook:
# Call the child notebook with custom parameters
result = dbutils.notebook.run("child_notebook", timeout_seconds=300, arguments={"region": "west", "date": "2024-06-01"})
print(result)
Expected output in the parent notebook:
Processing data for region=west on date=2024-06-01
Example 3: Parameterizing output paths (sink)
dbutils.widgets.text("output_table", "default_sales")
output_table = dbutils.widgets.get("output_table")
# Use the parameter as a table name
filtered_df.write.mode("overwrite").saveAsTable(output_table)
print(f"Wrote to {output_table}")
Pro tip: When passing parameters via
dbutils.notebook.run, values are always strings. If you need a list or dict, serialize withjson.dumps()on the sender side andjson.loads()on the receiver.
Compare options / when to choose what
| Approach | When to use | Pros | Cons |
|---|---|---|---|
Widgets (dbutils.widgets.*) |
Interactive exploration, job parameters, UI-driven runs | Built-in UI controls, easy for non-technical users | Values are strings, need type casting |
dbutils.notebook.run() arguments |
Orchestrating multiple notebooks in a pipeline | Pass parameters programmatically, return results | Harder to debug, no UI for inputs |
| Environment variables (via secrets) | Static configuration, not user-focused | Keeps secrets out of code | Not user-friendly for ad-hoc runs |
In a job, you can also define job parameters that are automatically available as widgets. This is the cleanest way to parameterize production runs.
Troubleshooting & edge cases
- Parameter values are always strings: If you pass
5it comes as"5". You must convert to integer or date and handleValueErrorfor bad input. - Widget name mismatch: If the parent passes
regionbut the child expectsregion_name, the widget just returns the default (and you might not notice). Always log the received parameters. - SQL injection: Never concatenate strings into SQL without validation. Use
spark.table()orcolumnreferences, or at least escape quotes. - Widget persists across runs: If you don't remove widgets, old values might remain. Use
dbutils.widgets.removeAll()at the end if needed. dbutils.notebook.run()timeout: The default is 120 seconds; set higher for long-running child notebooks, or you'll get a timeout error.
What you learned & what's next
You now understand what use parameters to parameterize notebooks means in Databricks: you can create reusable notebooks by exposing inputs through widgets, retrieving them with dbutils.widgets.get(), and passing them programmatically with dbutils.notebook.run(). You've completed a hands-on exercise that filters and writes data based on parameters, and you've seen how to avoid common pitfalls.
Next up: In the next lesson, you'll learn how to orchestrate multiple notebooks into a pipeline using Databricks workflows — where parameterization becomes essential for maintaining clean, flexible ETL jobs.
Keep your notebooks DRY (Don't Repeat Yourself), and parameterize early so you never maintain clones again.
Practice recap
Mini exercise: Modify the hands-on example so that date_from and date_to are passed from a parent notebook using dbutils.notebook.run(). Run it for two different date ranges and verify the row counts change. Then add a third parameter region as a dropdown widget with "all" as the default, and apply it as a filter in your query.
Common mistakes
- Forgetting to type-cast widget values —
dbutils.widgets.get()always returns a string, sodate_fromis"2024-01-01"not a date object; convert withdatetime.strptimeor similar. - Mismatching widget names between parent and child notebooks — if you pass
regionbut the child readsregion_name, the child silently uses the default, causing data errors. - Building SQL strings directly with user input — risk of SQL injection; use
spark.table()or parameterized queries instead of concatenation. - Not removing widgets after a run — leftover widget values can interfere with subsequent jobs; use
dbutils.widgets.removeAll()at the end. - Passing complex structures (lists/dicts) as arguments without serialization —
dbutils.notebook.run()only accepts strings; encode withjson.dumps()and decode on the other side.
Variations
- Job parameters: Define parameters in the Databricks Jobs UI, which automatically appear as widgets in your notebook — the cleanest way to set runtime inputs in production.
- Environment variables: Use
dbutils.secrets.get()to fetch configuration values, useful for non-interactive runs where parameters are fixed. - Dynamic widget types: Use
dbutils.widgets.dropdown()ordbutils.widgets.combobox()to constrain user input to predefined choices, reducing validation errors.
Real-world use cases
- A single ETL notebook that loads daily sales data for any given date — parameterized by
date_fromanddate_to, invoked by a scheduled job with changing dates. - A multi-tenant reporting pipeline where the same aggregation notebook is called for dozens of regions, each invocation passing a different
regionand output table name. - A backfill operation that re-processes historical data by running a parameterized notebook repeatedly with different
yearandmonthparameters, without modifying code.
Key takeaways
- Notebook parameters turn static code into reusable functions, eliminating copy-paste maintenance.
dbutils.widgets.*creates user-facing inputs;dbutils.widgets.get()retrieves them as strings.dbutils.notebook.run()lets one notebook call another, passing parameters programmatically — essential for pipelines.- Always type-cast and validate widget values to avoid silent logical errors.
- Job parameters provide a production-friendly way to inject inputs into notebooks.
- Name your parameters consistently and document them, because they are your notebook's API.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.