Azure Data Factory Triggers Explained: Schedule, Tumbling Window, and Event-Based Triggers
You built the pipeline. It works perfectly in Debug mode. But how do you make it run automatically at 2 AM every day? Or trigger it when a file lands in your data lake? Or process data in hourly windows that never miss a beat?
That is what triggers do. They are the scheduling and event engine of Azure Data Factory and Synapse Pipelines. And choosing the wrong trigger type is one of the most common mistakes in production pipeline design.
This guide covers all three trigger types with real-world scenarios, step-by-step setup, and the critical differences that determine which one to use.
Table of Contents
- What Are Triggers?
- The Three Trigger Types
- Schedule Trigger
- Tumbling Window Trigger
- Event-Based Trigger (Storage Events)
- Comparison Table: All Three Types
- Trigger Parameters: Passing Data to Pipelines
- Managing Triggers: Start, Stop, and Monitor
- Common Trigger Patterns
- Trigger vs Debug vs Manual Run
- Common Mistakes
- Interview Questions
- Wrapping Up
What Are Triggers?
A trigger defines when a pipeline runs. Without a trigger, pipelines only run when you manually click Debug or Trigger Now.
Triggers are separate resources from pipelines. One trigger can start one or more pipelines. One pipeline can have multiple triggers. They are loosely coupled.
Trigger: TR_Daily_2AM (Schedule)
|-- starts PL_Copy_SqlToADLS
|-- starts PL_Cleanup_OldFiles
Trigger: TR_FileArrival (Event)
|-- starts PL_Process_NewFile
Pipeline: PL_Copy_SqlToADLS
|-- triggered by TR_Daily_2AM (schedule)
|-- triggered by TR_Hourly_Refresh (another schedule)
|-- can also be run manually
The Three Trigger Types
| Type | Fires When | Best For |
|---|---|---|
| Schedule | At a fixed time/interval | Daily ETL, hourly refreshes, weekly reports |
| Tumbling Window | At a fixed time/interval WITH state tracking | Time-series processing, guaranteed exactly-once per window |
| Event-Based | When a file is created/deleted in storage | File-driven ingestion, real-time-ish processing |
Schedule Trigger
What It Does
Fires at a fixed schedule — daily, hourly, every 15 minutes, specific days of the week, etc. This is the simplest and most commonly used trigger.
When to Use
- Daily ETL pipeline at 2 AM
- Hourly data refresh
- Weekly report generation
- Any fixed-schedule recurring job
Setting Up a Schedule Trigger
- Open your pipeline in ADF/Synapse Studio
- Click Add trigger > New/Edit
- Click + New
- Configure:
- Name:
TR_Daily_2AM - Type: Schedule
- Start date:
2026-04-07T02:00:00Z - Recurrence: Every 1 Day
- Time zone: Eastern Standard Time (or your preferred zone)
- End date: No end (or set a specific end date)
- Click OK > Publish
Advanced Schedule Options
Run at specific times:
Every day at 2:00 AM, 8:00 AM, and 6:00 PM
Recurrence: 1 Day
At these hours: 2, 8, 18
At these minutes: 0
Run on specific days:
Every Monday and Friday at 9:00 AM
Recurrence: 1 Week
On these days: Monday, Friday
At these hours: 9
Run every 15 minutes during business hours:
Recurrence: 1 Day
At these hours: 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
At these minutes: 0, 15, 30, 45
Schedule Trigger Limitations
- No state tracking — if the pipeline fails, the trigger does not know. The next scheduled run simply starts on time regardless.
- No backfill — if the trigger was paused for 3 days, it does not catch up on missed runs.
- No dependency — cannot wait for a previous run to complete before starting the next one.
Tumbling Window Trigger
What It Does
Similar to Schedule but with state tracking per time window. Each window is an independent, non-overlapping time slice that is processed exactly once.
When to Use
- Processing data in fixed time windows (hourly, daily) where every window MUST be processed
- When you need backfill — catch up on missed windows
- When you need dependency chaining — one pipeline’s window depends on another’s
- Time-series data processing where gaps are not acceptable
How It Differs from Schedule
Schedule Trigger:
2 AM: Run pipeline --> FAILED
2 AM next day: Run pipeline (no retry of yesterday's failure)
Result: Yesterday's data is LOST unless manually rerun
Tumbling Window Trigger:
Window [2026-04-07 00:00, 2026-04-08 00:00]: Run pipeline --> FAILED
Automatic retry: Rerun the failed window
Window [2026-04-08 00:00, 2026-04-09 00:00]: Run normally
Result: Every window is processed, no data loss
Setting Up a Tumbling Window Trigger
- Click Add trigger > New/Edit > + New
- Configure:
- Name:
TR_Hourly_Window - Type: Tumbling Window
- Start date:
2026-04-01T00:00:00Z - Recurrence: Every 1 Hour
- Max concurrency: 1 (process one window at a time)
- Retry policy: 3 retries with 15-minute intervals
- Delay: 0 minutes (start immediately when window opens)
- Click OK > Publish
Tumbling Window Parameters
The trigger automatically provides window start and end times to the pipeline:
@trigger().outputs.windowStartTime --> "2026-04-07T00:00:00Z"
@trigger().outputs.windowEndTime --> "2026-04-07T01:00:00Z"
Use these in your pipeline to process only the data for that specific window:
SELECT * FROM orders
WHERE order_date >= '@{trigger().outputs.windowStartTime}'
AND order_date < '@{trigger().outputs.windowEndTime}'
Backfill with Tumbling Window
If you create a trigger with a start date in the past:
Start date: 2026-01-01
Current date: 2026-04-07
Recurrence: Daily
The trigger automatically creates windows for every day from Jan 1 to Apr 7 and starts processing them. This is automatic backfill — no manual intervention needed.
Window Dependencies
Tumbling Window triggers support dependencies between pipelines:
Pipeline A (hourly window) must complete before Pipeline B starts for the same window
TR_Window_A: Process raw data for [00:00-01:00]
TR_Window_B: Depends on TR_Window_A, transforms data for [00:00-01:00]
Configure in the trigger’s dependency settings.
Tumbling Window Concurrency
Max concurrency = 1: Windows are processed one at a time, in order. Safest option.
Max concurrency = 5: Up to 5 windows can process simultaneously. Faster for backfill but requires idempotent pipelines.
Event-Based Trigger (Storage Events)
What It Does
Fires when a file is created or deleted in Azure Blob Storage or ADLS Gen2. The pipeline starts automatically when data arrives.
When to Use
- Process files as soon as they land in the data lake
- Ingest data from external systems that drop files on a schedule
- React to upstream pipeline outputs
- Near-real-time file processing
Setting Up an Event-Based Trigger
- Click Add trigger > New/Edit > + New
- Configure:
- Name:
TR_NewFile_Bronze - Type: Storage events
- Storage account: select your ADLS Gen2 account
- Container:
datalake - Blob path begins with:
bronze/incoming/ - Blob path ends with:
.parquet - Event: Blob created
- Ignore empty blobs: Yes
- Click OK > Publish
Event Trigger Parameters
The trigger provides the file details to the pipeline:
@trigger().outputs.body.folderPath --> "bronze/incoming/"
@trigger().outputs.body.fileName --> "customers_20260407.parquet"
Use these to process the specific file that triggered the pipeline:
Copy Activity Source:
FolderPath: @trigger().outputs.body.folderPath
FileName: @trigger().outputs.body.fileName
Filtering Events
You can filter which files trigger the pipeline:
Blob path begins with: bronze/incoming/ (only files in this folder)
Blob path ends with: .parquet (only Parquet files)
This prevents the pipeline from triggering on temp files, logs, or irrelevant uploads.
Event Trigger Requirements
- Storage account must have Event Grid resource provider registered
- ADF/Synapse needs appropriate permissions on the storage account
- There is a slight delay (seconds to a minute) between file creation and trigger firing
- If multiple files arrive simultaneously, the trigger fires for EACH file
Comparison Table: All Three Types
| Feature | Schedule | Tumbling Window | Event-Based |
|---|---|---|---|
| Fires on | Fixed time/interval | Fixed time/interval | File created/deleted |
| State tracking | No | Yes (per window) | No |
| Backfill | No | Yes (automatic) | No |
| Retry failed windows | No | Yes (configurable) | No (pipeline retry only) |
| Window parameters | No | Yes (windowStart, windowEnd) | No (file info instead) |
| Dependencies | No | Yes (between triggers) | No |
| Concurrency control | No (overlapping runs possible) | Yes (max concurrency) | Limited |
| File info to pipeline | No | No | Yes (folder, fileName) |
| Best for | Simple scheduled ETL | Time-series, guaranteed processing | File-driven ingestion |
| Complexity | Low | Medium | Medium |
Trigger Parameters: Passing Data to Pipelines
Schedule Trigger Parameters
Schedule triggers can pass static parameters to pipelines:
{
"parameters": {
"environment": "production",
"sourceSchema": "SalesLT"
}
}
Tumbling Window Parameters
Access window times in the pipeline:
Pipeline parameter: windowStart = @trigger().outputs.windowStartTime
Pipeline parameter: windowEnd = @trigger().outputs.windowEndTime
Event Trigger Parameters
Access file details in the pipeline:
Pipeline parameter: folderPath = @trigger().outputs.body.folderPath
Pipeline parameter: fileName = @trigger().outputs.body.fileName
Managing Triggers: Start, Stop, and Monitor
Starting a Trigger
After creating and publishing a trigger, it must be started:
- Go to Manage > Triggers
- Find your trigger
- Click the Start button (or toggle)
A trigger that is created but not started will not fire.
Stopping a Trigger
Before deploying changes via CI/CD, stop all triggers first:
az datafactory trigger stop --resource-group rg-dev --factory-name adf-dev --name TR_Daily_2AM
This prevents pipelines from running during deployment. Restart after deployment completes.
Monitoring Trigger Runs
- Go to Monitor > Trigger runs
- See which triggers fired, when, and which pipelines they started
- Filter by status (Succeeded, Failed, In Progress)
Common Trigger Patterns
Pattern 1: Daily ETL with Notification
TR_Daily_2AM (Schedule, daily at 2 AM)
|-- PL_Daily_ETL
|-- Copy all tables
|-- Run audit logging
|-- Web Activity: send Slack notification with results
Pattern 2: Hourly Incremental with Tumbling Window
TR_Hourly_Window (Tumbling Window, every 1 hour)
|-- PL_Incremental_Load
|-- Uses @trigger().outputs.windowStartTime as the delta range
|-- Processes only data from that specific hour
|-- Guaranteed: every hour is processed exactly once
Pattern 3: File Landing Zone
TR_NewFile (Event, blob created in /incoming/*.csv)
|-- PL_Process_File
|-- Copy file from /incoming/ to /bronze/ (with date partition)
|-- Delete original from /incoming/
|-- Log processing result
Pattern 4: Multi-Trigger Pipeline
PL_Copy_SqlToADLS is triggered by:
- TR_Daily_2AM (daily at 2 AM for full refresh)
- TR_Manual (via REST API for ad-hoc runs)
- TR_Upstream_Complete (when upstream pipeline finishes)
Trigger vs Debug vs Manual Run
| Method | When to Use | Parameters | Monitored |
|---|---|---|---|
| Debug | Development and testing | Manually entered | Yes (output pane) |
| Trigger Now | One-time manual run | Manually entered | Yes (Monitor tab) |
| Trigger (scheduled) | Automated production runs | From trigger config | Yes (Monitor tab) |
Debug runs are NOT captured in the Monitor tab’s Pipeline runs section (they appear in Debug output only). Trigger Now and scheduled triggers appear in Monitor.
Common Mistakes
1. Forgetting to Start the Trigger
Creating and publishing a trigger does not start it. You must explicitly start it.
2. Overlapping Schedule Trigger Runs
If a pipeline takes 2 hours but the schedule trigger fires every hour, multiple instances run simultaneously:
2 AM: Pipeline starts (takes 2 hours)
3 AM: Pipeline starts again (previous still running)
Result: Two copies writing to the same destination simultaneously
Fix: Use Tumbling Window trigger with max concurrency = 1, or add a check at the start of the pipeline.
3. Not Stopping Triggers Before CI/CD Deployment
Triggers firing during ARM template deployment can cause failures. Always stop triggers in the pre-deployment script and restart in post-deployment.
4. Event Trigger Firing for Every File
If a Spark job writes 100 Parquet files to a folder, the event trigger fires 100 times. Each file creates a separate pipeline run.
Fix: Filter by specific file names (e.g., _SUCCESS file) or use a Schedule/Tumbling Window trigger instead.
5. Not Using Tumbling Window for Time-Series Data
Using a Schedule trigger for hourly processing means missed hours are lost. Tumbling Window automatically retries failed windows and backfills gaps.
Interview Questions
Q: What are the three trigger types in ADF? A: Schedule (fixed time/interval), Tumbling Window (time-based with state tracking and backfill), and Event-Based (fires when a file is created/deleted in storage).
Q: When would you use a Tumbling Window trigger instead of a Schedule trigger? A: When you need guaranteed processing of every time window, automatic retry of failed windows, backfill for historical data, or dependency chaining between pipelines. Tumbling Window tracks state per window; Schedule does not.
Q: How does an Event-Based trigger work? A: It monitors an Azure Storage container for file creation or deletion events. When a matching file appears (based on path prefix and suffix filters), the trigger fires and passes the file path and name to the pipeline as parameters.
Q: What happens if a Schedule trigger fires while the previous run is still executing? A: A new pipeline run starts regardless. This can cause concurrent runs writing to the same destination. Use Tumbling Window with max concurrency = 1 to prevent this.
Q: How do you pass the window time range to a pipeline from a Tumbling Window trigger?
A: Use @trigger().outputs.windowStartTime and @trigger().outputs.windowEndTime as pipeline parameters. The pipeline uses these to query only the data for that specific window.
Q: Why must you stop triggers before CI/CD deployment? A: Triggers firing during deployment can run pipelines with half-deployed resources, causing failures or data corruption. Stop all triggers in pre-deployment, deploy, then restart in post-deployment.
Wrapping Up
Choosing the right trigger type is critical for production pipelines:
- Schedule for simple, fixed-time runs where missed runs are acceptable
- Tumbling Window for time-series processing where every window must be processed
- Event-Based for file-driven ingestion where you react to data arrival
Most production data platforms use a combination of all three. Master them, and your pipelines run reliably without manual intervention.
Related posts: – What is Azure Data Factory? – Metadata-Driven Pipeline in ADF – Incremental Data Loading – CI/CD with GitHub – Top 15 ADF Interview Questions
Naveen Vuppula is a Senior Data Engineering Consultant and app developer based in Ontario, Canada. He writes about Python, SQL, AWS, Azure, and everything data engineering at DriveDataScience.com.