Home › DevOps › Control-M for Beginners: Jobs, Folders, Conditions & New Day Explained
Beginner 3 min · October 30, 2026

Control-M for Beginners: Jobs, Folders, Conditions & New Day Explained

Control-M beginner tutorial: learn how jobs, folders, conditions, and the New Day actually work in production—with real war stories and fixes.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
✓ Production
production tested
November 03, 2026
last updated
2,099
articles · all by Naren
Before you start⏱ 35 min
  • ✓Basic familiarity with what a scheduled task or cron job is
  • ✓Comfort with the idea of a batch process (e.g., a nightly script that moves files)
  • ✓No prior Control-M experience required
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
⚡Quick Answer

Control-M schedules and orchestrates batch jobs across servers, databases, and applications. You define jobs inside folders, link them with conditions (like 'job A must finish before job B starts'), and the New Day process rolls the schedule forward each day so the same workflow runs reliably without manual intervention.

✦ Definition~90s read
What is Control-M Tutorial?

Control-M is an enterprise batch scheduling and workload automation platform. It defines jobs (the work), folders (the containers), conditions (the dependencies), and the New Day (the daily reset that makes it all repeatable).

★
Think of Control-M as an air traffic control tower for your nightly batch processes.
Plain-English First

Think of Control-M as an air traffic control tower for your nightly batch processes. Jobs are the planes, folders are the flight paths grouped by destination, conditions are the radio calls that say 'I've landed, you're cleared to take off,' and the New Day is the daily shift change where the tower resets the board for tomorrow's flights. Without the tower, planes would take off whenever they want and crash into each other.

Most Control-M tutorials start with a definition and end with a screenshot of the GUI. That's why beginners still can't explain why their job didn't run at 2 AM. The truth: Control-M is not a cron replacement—it's a dependency engine, and if you don't understand conditions and the New Day, you're just guessing.

Here's the problem it solves: in a real enterprise, you have hundreds of jobs that must run in a specific order across different servers, databases, and time zones. Cron can't handle 'wait for the file to arrive, then run the load, then trigger the report only if the load succeeded.' Control-M can. It's the difference between a to-do list and a project plan with dependencies.

After this article, you'll be able to read a Control-M job flow, explain why a job is waiting, create a folder with conditions, and understand what happens when the New Day rolls over. You'll also know the exact mistakes that cause jobs to hang forever—and how to fix them.

Jobs: The Atoms of Control-M

A job is the smallest unit of work in Control-M. It's a command, a script, a database procedure—anything that can run on a server. But unlike cron, a Control-M job carries metadata: what conditions it needs, what conditions it sets, what to do on failure, and which folder it belongs to. That metadata is what turns a dumb script into a schedulable, observable unit.

In production, jobs are rarely standalone. A typical nightly batch has a job that extracts data, one that transforms it, and one that loads it. Each job is a separate entity, but they're linked by conditions. The job itself doesn't know about the others—Control-M orchestrates the flow.

DailyRevenueExtract.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// io.thecodeforge — DevOps tutorial

// This is a Control-M job definition (JSON representation for clarity)
// In the GUI, you'd fill these fields in the job properties.
{
  "jobName": "DAILY_REVENUE_EXTRACT",
  "folder": "FINANCE_DAILY",
  "command": "/opt/scripts/extract_revenue.sh",
  "host": "etl-server-01",
  "runAs": "etluser",
  "conditions": {
    "in": ["FILE_ARRIVED"],          // Wait for this condition before running
    "out": ["EXTRACT_COMPLETE"]       // Set this condition when done
  },
  "onFailure": {
    "action": "NOTIFY",
    "email": "etl-team@company.com"
  },
  "maxWait": 1,                       // How many days an unsubmitted job stays in Active Jobs
  "timeout": "02:00"                  // Fail if not done in 2 hours
}
Output
Job DAILY_REVENUE_EXTRACT created in folder FINANCE_DAILY.
Status: Wait Condition (waiting for FILE_ARRIVED).
⚠ Production Trap:
Never set a job to run more than once per day unless you have a very good reason. A job that runs twice can double-load your data warehouse and corrupt aggregates. I've seen a payments reconciliation job run twice and produce a $2M discrepancy that took three days to untangle.

Folders: Grouping Jobs for Sanity and Control

A folder is a container for jobs. It's the equivalent of a project folder in your IDE—except it also carries scheduling and dependency rules. Folders let you group related jobs (e.g., all finance jobs), set a common schedule (e.g., run every weekday at 1 AM), and define folder-level conditions that apply to all jobs inside.

Why folders matter: without them, you'd have hundreds of loose jobs with no structure. Folders give you a single point of control. Need to disable all finance jobs for a holiday? Disable the folder. Need to set a condition that all jobs in the folder must wait for? Set it at the folder level. It's the difference between managing a team and managing a crowd.

FinanceDailyFolder.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// io.thecodeforge — DevOps tutorial

// Folder definition (JSON representation)
{
  "folderName": "FINANCE_DAILY",
  "schedule": {
    "type": "WEEKDAYS",
    "startTime": "01:00",
    "timezone": "America/New_York"
  },
  "conditions": {
    "in": ["BATCH_WINDOW_OPEN"],      // All jobs in folder wait for this
    "out": ["FINANCE_DAILY_DONE"]     // Set when all jobs complete
  },
  "jobs": [
    "DAILY_REVENUE_EXTRACT",
    "DAILY_REVENUE_TRANSFORM",
    "DAILY_REVENUE_LOAD"
  ],
  "onFailure": {
    "action": "HALT_FOLDER",           // Stop all jobs if any fails
    "notify": "finance-oncall@company.com"
  }
}
Output
Folder FINANCE_DAILY created with 3 jobs.
Schedule: Weekdays at 01:00 America/New_York.
Folder condition: waits for BATCH_WINDOW_OPEN, sets FINANCE_DAILY_DONE.
💡Senior Shortcut:
Use folder-level conditions to gate entire workflows. For example, set BATCH_WINDOW_OPEN only after your upstream data provider confirms the file is ready. Then every job in the folder automatically waits—no need to add the condition to each job individually.

Conditions: The Glue That Holds Workflows Together

Conditions are the heart of Control-M. They're boolean flags—either set or not set—that jobs use to communicate. A job can wait for one or more conditions (in-conditions) and set one or more conditions when it finishes (out-conditions). This is how you build dependencies without hardcoding job names.

The problem conditions solve: in a cron world, you'd schedule job B at 2 AM hoping job A finishes by then. If A runs long, B fails or runs on stale data. With conditions, B waits until A explicitly says 'I'm done' by setting a condition. It's event-driven scheduling, not time-based guessing.

ConditionFlow.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// io.thecodeforge — DevOps tutorial

// Job A: Extract data and set condition
{
  "jobName": "EXTRACT_DATA",
  "command": "/opt/scripts/extract.sh",
  "conditions": {
    "out": ["EXTRACT_DONE"]
  }
}

// Job B: Wait for EXTRACT_DONE, then transform
{
  "jobName": "TRANSFORM_DATA",
  "command": "/opt/scripts/transform.sh",
  "conditions": {
    "in": ["EXTRACT_DONE"],
    "out": ["TRANSFORM_DONE"]
  }
}

// Job C: Wait for TRANSFORM_DONE, then load
{
  "jobName": "LOAD_DATA",
  "command": "/opt/scripts/load.sh",
  "conditions": {
    "in": ["TRANSFORM_DONE"],
    "out": ["LOAD_DONE"]
  }
}
Output
Job EXTRACT_DATA: sets EXTRACT_DONE on success.
Job TRANSFORM_DATA: waits for EXTRACT_DONE, sets TRANSFORM_DONE.
Job LOAD_DATA: waits for TRANSFORM_DONE, sets LOAD_DONE.
⚠ Never Do This:
Don't use conditions as a substitute for proper error handling. A condition is not a success signal—it's just a flag. If EXTRACT_DATA fails but still sets EXTRACT_DONE (because you forgot to add onFailure: DO_NOT_SET), downstream jobs will run on bad data. Always tie out-conditions to job success.

The New Day: Resetting the Clock Without Losing Your Mind

The New Day is Control-M's daily reset. At a configured time (usually midnight or early morning), Control-M rolls the schedule forward: it clears old conditions, resets job statuses, and prepares the next day's run. Without it, jobs would only run once and then sit in 'Completed' forever.

The New Day is also the source of many beginner headaches. If it fails or is delayed, all jobs for the new day stay in 'Wait Schedule' and nothing runs. If it runs twice, you get duplicate jobs. Understanding the New Day is non-negotiable for anyone operating Control-M in production.

NewDayConfig.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// io.thecodeforge — DevOps tutorial

// New Day configuration (simplified)
{
  "newDayTime": "00:30",
  "timezone": "America/New_York",
  "action": "RESET_CONDITIONS",       // Clear all conditions from previous day
  "retainConditions": ["PERMANENT_FLAG"], // Except these
  "onFailure": {
    "action": "ALERT",
    "email": "controlm-admin@company.com"
  },
  "maxDelay": "02:00"                 // If New Day hasn't run by 2:30 AM, alert
}
Output
New Day scheduled for 00:30 America/New_York.
Conditions reset daily except PERMANENT_FLAG.
Alert if not completed by 02:30.
🔥Interview Gold:
The New Day doesn't just reset time—it resets state. Conditions from yesterday are gone. If you have a job that depends on a condition set by a weekly job, that condition won't exist on other days unless you explicitly retain it or use a different mechanism (like a file watcher).

Putting It All Together: A Realistic Nightly Batch

Let's walk through a realistic finance batch: a file arrives from the billing system, you extract it, transform it, load it into the warehouse, and generate a report. Each step is a job, grouped in a folder, linked by conditions, and reset daily by the New Day.

This is the pattern you'll see in 80% of enterprise Control-M setups. Master this, and you can read any job flow.

FinanceBatchFlow.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// io.thecodeforge — DevOps tutorial

// Folder: FINANCE_DAILY
// Schedule: Weekdays at 01:00

// Job 1: Wait for file arrival condition (set by external file watcher)
{
  "jobName": "WAIT_FOR_BILLING_FILE",
  "command": "/opt/scripts/check_file.sh /data/incoming/billing.csv",
  "conditions": {
    "in": ["BILLING_FILE_ARRIVED"],
    "out": ["BILLING_FILE_READY"]
  },
  "timeout": "01:00"
}

// Job 2: Extract
{
  "jobName": "EXTRACT_BILLING",
  "command": "/opt/scripts/extract_billing.sh",
  "conditions": {
    "in": ["BILLING_FILE_READY"],
    "out": ["BILLING_EXTRACTED"]
  }
}

// Job 3: Transform
{
  "jobName": "TRANSFORM_BILLING",
  "command": "/opt/scripts/transform_billing.sh",
  "conditions": {
    "in": ["BILLING_EXTRACTED"],
    "out": ["BILLING_TRANSFORMED"]
  }
}

// Job 4: Load
{
  "jobName": "LOAD_BILLING",
  "command": "/opt/scripts/load_billing.sh",
  "conditions": {
    "in": ["BILLING_TRANSFORMED"],
    "out": ["BILLING_LOADED"]
  }
}

// Job 5: Report
{
  "jobName": "GENERATE_REPORT",
  "command": "/opt/scripts/generate_report.sh",
  "conditions": {
    "in": ["BILLING_LOADED"],
    "out": ["REPORT_READY"]
  }
}
Output
Flow: WAIT_FOR_BILLING_FILE -> EXTRACT_BILLING -> TRANSFORM_BILLING -> LOAD_BILLING -> GENERATE_REPORT
Each job waits for the previous job's out-condition.
If any job fails, downstream jobs wait indefinitely (unless timeout set).
💡Production Trap:
Always set a timeout on the first job in a flow. If the file never arrives, the job waits forever and the entire batch is stuck. A timeout of 1 hour with an alert lets you catch the issue before the business day starts.

Common Beginner Mistakes (And How to Avoid Them)

Most Control-M failures aren't complex—they're simple mistakes repeated. Here are the ones I see most often, with exact fixes.

Mistakes.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// io.thecodeforge — DevOps tutorial

// Mistake 1: Forgetting to set out-condition on success
// Symptom: Downstream job waits forever
// Fix: Add "out": ["CONDITION_NAME"] and ensure job sets it only on success

// Mistake 2: Using the same condition name in multiple folders
// Symptom: Job runs unexpectedly because another folder set the condition
// Fix: Prefix conditions with folder name, e.g., FINANCE_EXTRACT_DONE

// Mistake 3: No protection against duplicate ordering
// Symptom: Job runs multiple times if it is ordered twice
// Fix: Control-M has no "maxRuns" attribute; use a condition or a quantitative resource to prevent duplicate runs

// Mistake 4: Ignoring New Day failures
// Symptom: All jobs stuck in 'Wait Schedule'
// Fix: Monitor New Day status; set up alert if not completed by a threshold
Output
No output—these are configuration guidelines.
⚠ The Classic Bug:
Condition names are global across the entire Control-M environment. If you have two folders that both set EXTRACT_DONE, jobs in one folder might trigger jobs in the other. Always namespace your conditions: FOLDERNAME_CONDITIONNAME.
● Production incidentPOST-MORTEMseverity: high

The Condition That Never Came

Symptom
At 3 AM, the daily revenue report job sat in 'Wait Condition' for six hours. The downstream finance team got nothing. No errors in the job log—just silence.
Assumption
The team assumed the report job was broken. They restarted it three times. Same result: waiting.
Root cause
The upstream job that was supposed to set the condition DAILY_LOAD_OK had been disabled by a well-meaning admin who thought it was a duplicate. The condition was never set, so the report job waited forever. Control-M doesn't time out conditions by default—it waits indefinitely.
Fix
Re-enable the upstream job, run it manually to set the condition, and add a Shout/notification 'when late submission' (or an SLA) on the downstream job so you're alerted if it waits too long. Also add a 'Condition' check in the report job's pre-processing script to fail fast if the condition is missing after a threshold.
Key lesson
  • A condition is a promise.
  • If the promiser is gone, the promise never resolves—and Control-M will wait until the heat death of the universe.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.4 entries
Symptom · 01
Job stuck in 'Wait Condition' for hours
→
Fix
1. Check job's in-conditions: ctmcontb -LIST <condition_name> "*". 2. If condition not set, find producer job and check its status/log. 3. If producer failed, fix and rerun. 4. If producer was deleted, manually set condition: ctmcontb -ADD <condition_name> <MMDD> or add dummy job.
Symptom · 02
New Day didn't run, all jobs in 'Wait Schedule'
→
Fix
1. Check New Day status in the Monitoring domain of the Control-M web interface. 2. If stuck, verify the site's configured New Day time and timezone, then check the Active Jobs database for jobs still waiting. 3. Verify New Day time and timezone. 4. Check for errors in the New Day log: $CONTROLM_HOME/log/newday.log.
Symptom · 03
Job ran twice in one day
→
Fix
1. Check if New Day ran twice: ctmcontb -LIST "" "". 2. Check the job's scheduling criteria and whether it was ordered more than once (e.g. via ctmpsm or the Monitoring domain). 3. Ensure the job is ordered only once per day. 4. If duplicate output, clean up manually and add pre-run check script.
Symptom · 04
Condition never resolves because producer job was deleted
→
Fix
1. Identify orphaned condition: ctmcontb -LIST "" "". 2. Delete condition: ctmcontb -DELETE <condition_name> <date>. 3. Add dummy job to set condition or fix dependency chain.
★ Control-M Tutorial for Beginners: Jobs, Folders, Conditions and the New Day Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
Job stuck in `Wait Condition`−
Immediate action
Check if the required condition exists.
Commands
ctmcontb -LIST <condition_name> "*"
ctmpsm (no arguments, interactive menu) | grep <producer_job_name>
Fix now
If condition missing, run producer job manually or set condition: ctmcontb -ADD <condition_name> <MMDD>.
New Day not run, jobs in `Wait Schedule`+
Immediate action
Check New Day status.
Commands
ctmpsm
ctmorder -FOLDER <folder> -NAME <job> -ODATE ODAT -FORCE y
Fix now
Force New Day if no active jobs; otherwise wait or investigate blockage.
Job ran twice, duplicate output+
Immediate action
Check job's run history.
Commands
ctmpsm (no arguments, interactive menu) or use the Monitoring domain in the Control-M web interface to browse active jobs; for a specific job, ctmwhy <orderno>
ctmpsm -UPDATEAJF <orderno> HOLD
Fix now
Hold the duplicate copy in Active Jobs (ctmpsm -UPDATEAJF <orderno> HOLD) before it runs, then delete it; clean up any duplicate output by hand.
Condition never resolves, producer job deleted+
Immediate action
Find orphaned condition.
Commands
ctmcontb -LIST <condition_name> "*"
ctmcontb -DELETE <condition_name> <date>
Fix now
Delete condition and add dummy job to set it, or fix dependency chain.
FeatureControl-MCron
Dependency managementConditions (event-driven)Time-based only
Job groupingFolders with shared schedulesNone
Failure handlingOn-failure actions, alerts, retriesManual scripting
Daily resetNew Day processNone (cron runs forever)
VisibilityGUI, logs, statusesLog files only
Cross-platformYes (agents on many OS)Per-host
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
DailyRevenueExtract.devops{Jobs
FinanceDailyFolder.devops{Folders
ConditionFlow.devops{Conditions
NewDayConfig.devops{The New Day
FinanceBatchFlow.devops{Putting It All Together

Key takeaways

1
Conditions are promises—if the producer job is gone, the promise never resolves and downstream jobs wait forever. Always set timeouts.
2
Namespace your condition names with the folder name to avoid cross-folder triggering. FINANCE_EXTRACT_DONE is safer than EXTRACT_DONE.
3
The New Day procedure runs once a day at the site's configured New Day time and orders every job whose scheduling criteria match that date into the Active Jobs database; it does not reset conditions (old conditions are cleaned up by date, e.g. the daily condition cleanup). If it fails, nothing runs. Monitor it like a production service.
4
Guard against duplicate runs. A job ordered twice (a manual order plus New Day) runs twice, so make jobs idempotent and order them manually only with a reason.
5
Folders are your primary unit of control—use folder-level conditions and schedules to manage groups of jobs, not individual jobs.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How does Control-M handle a condition that is set by multiple jobs?
Q02SENIOR
When would you choose Control-M over a simple cron job?
Q03SENIOR
What happens if the New Day runs while jobs from the previous day are st...
Q04JUNIOR
What is the difference between a job's in-condition and out-condition?
Q05SENIOR
A job is stuck in 'Wait Condition' and the producer job shows 'Completed...
Q06SENIOR
How would you design a Control-M workflow for a multi-step ETL process t...
Q01 of 06SENIOR

How does Control-M handle a condition that is set by multiple jobs?

ANSWER
Control-M conditions are boolean—set or not set. If multiple jobs set the same condition, the condition remains set until the New Day resets it (or it's manually deleted). This can cause jobs to trigger earlier than expected if one producer finishes early. Mitigation: use unique condition names per producer, or use 'quantitative' conditions (count-based) if you need to wait for N producers.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is the New Day in Control-M and why does it matter?
02
What's the difference between a Control-M job and a folder?
03
How do I fix a Control-M job stuck in 'Wait Condition'?
04
Can a Control-M job set multiple conditions?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
✓ Verified
production tested
November 03, 2026
last updated
2,099
articles · all by Naren
🔥

That's Control-M. Mark it forged?

3 min read · try the examples if you haven't

←
Previous
Git LF CRLF Warning Fix
1 / 4 · Control-M
Next
Control-M Job Stuck in Wait Condition: Condition Dates and ODAT Explained
→