LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1620 min read

JCL: The DD Statement

Learn how DD statements connect a program's internal file references to real datasets, how the DISP parameter (NEW/OLD/SHR/MOD) controls access, and how SYSOUT routes printed output.

Introduction

You now know how to identify a job (JOB) and how to say what should run (EXEC). The last piece of the core trio answers a question those two statements deliberately leave open: which actual datasets does this step read from and write to? That is the job of the DD statement — Data Definition — and it is where JCL connects the abstract file references inside a program to real, physical data sitting on disk or tape.

What a DD Statement Connects

Programs, including COBOL programs, are typically written without hardcoding the exact dataset name they will read or write. Instead, internally, a program refers to its files using short symbolic names (in COBOL, these are tied to SELECT...ASSIGN clauses). At execution time, JCL is what maps each of those symbolic names to a specific, real dataset — and that mapping is exactly what a DD statement provides.

The Core Idea

A program says "give me the file called TRANSIN" internally. The DD statement in the JCL running that step says "TRANSIN means PROD.TRANS.RAW, and here is how to access it." Change the DD statement, and the exact same compiled program can process an entirely different dataset without being touched or recompiled.

The name field of a DD statement — the ddname — is the symbolic name the program actually references internally. It is not arbitrary from the program's point of view: the ddname must exactly match what the program expects (in COBOL, this is established through the SELECT...ASSIGN TO clause pointing at that ddname). The rest of the DD statement then supplies the actual dataset name (DSN) and how it should be accessed.

A basic DD statement
//TRANSIN DD DSN=PROD.TRANS.RAW,DISP=SHR

Here, TRANSIN is the ddname the program looks for, PROD.TRANS.RAW is the real dataset being connected to it, and DISP=SHR (covered next) says this step only needs to read it, allowing other jobs to read it concurrently.

The DISP Parameter

DISP (disposition) is one of the most important parameters on any DD statement. It tells z/OS three things: the dataset's status when the step starts, what to do with it if the step ends normally, and what to do with it if the step abends. It is coded as up to three positional sub-parameters: DISP=(status,normal-disposition,abnormal-disposition).

Status ValueMeaning
NEWThe dataset does not exist yet; this step will create it
OLDThe dataset already exists, and this step needs exclusive access to it (no other job can use it at the same time)
SHRThe dataset already exists, and this step only needs to read it, allowing other jobs to access it concurrently
MODEither extend an existing dataset by appending to it, or create it if it does not exist yet
Disposition ValueMeaning
KEEPKeep the dataset on disk after the step, but do not add it to the system catalog
CATLGKeep the dataset and add (or confirm) its entry in the system catalog, so it can be found by name alone later
DELETERemove the dataset entirely
PASSKeep the dataset available for a later step in the same job, without finalizing its disposition yet
DISP examples
DISP=SHR -> Existing dataset, read-only sharing
DISP=(NEW,CATLG,DELETE) -> New dataset; keep+catalog on success, delete on failure
DISP=(OLD,KEEP,KEEP) -> Existing dataset, exclusive use; keep either way
DISP=(MOD,CATLG,DELETE) -> Append (or create); keep+catalog on success, delete on failure
Why the Three Sub-Parameters Matter

Separating the success and failure dispositions is deliberate: it is common to want a newly created dataset cataloged permanently if a step succeeds, but automatically cleaned up if the step fails partway through, so a failed job does not leave a corrupt, half-written dataset lying around under a name later jobs might mistake for good data.

SYSOUT: Routing Printed Output

Not every DD statement points at a permanent dataset. SYSOUT= directs output to the job's spooled print output instead, categorized by output class (the same kind of single-character class used by MSGCLASS on the JOB statement). This is the standard way reports, listings, and diagnostic output get produced without needing a permanent dataset allocated for them.

Two SYSOUT examples
//RPTOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=A
Reading it

Click Run to see what this code prints.

Space and DCB Attributes

When a DD statement creates a new dataset (DISP=NEW or MOD creating for the first time), it typically also needs to specify how much space to reserve and how the dataset's records are formatted. SPACE= requests an amount of storage (in tracks, cylinders, or blocks), often with a primary and secondary allocation so the dataset can grow if needed. DCB= (Data Control Block) attributes describe the physical record format — RECFM for record format (fixed or variable length, blocked or not), and LRECL for the logical record length.

Creating a new dataset with space and DCB attributes
//SORTOUT DD DSN=PROD.TRANS.SORTED,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(10,5),RLSE),
// DCB=(RECFM=FB,LRECL=100,BLKSIZE=0)
Reading it

Click Run to see what this code prints.

Referencing In-Stream Data with DD *

Sometimes a step needs a small amount of input data — control statements, a short list of values — that is not worth creating a separate permanent dataset for. DD * lets that data be embedded directly inside the JCL job stream itself, immediately following the DD statement, ending at a line containing only /* (or at the next JCL statement in modern systems).

In-stream data supplying sort control statements
//SYSIN DD *
SORT FIELDS=(1,10,CH,A)
/*

A Complete Example

One step using several DD techniques together
//STEP010 EXEC PGM=TRANPROC
//TRANSIN DD DSN=PROD.TRANS.SORTED,DISP=SHR
//MASTFILE DD DSN=PROD.CUSTMAST.KSDS,DISP=OLD
//TRANOUT DD DSN=PROD.TRANS.POSTED,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(20,10),RLSE),
// DCB=(RECFM=FB,LRECL=150)
//RPTOUT DD SYSOUT=*
//SYSIN DD *
RUNDATE=20260605
/*
Reading it

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Using DISP=OLD when SHR would do, unnecessarily locking a dataset and blocking other jobs (like online CICS access) that only need to read it.
  • Forgetting SPACE= or DCB= attributes when creating a brand-new dataset, causing an allocation failure.
  • Mismatching the ddname coded in JCL against the one the program actually expects internally — even a perfect DSN is useless if the ddname link is wrong.
  • Leaving off the closing /* on in-stream DD * data, which can cause the system to keep reading subsequent JCL lines as if they were data.

Best Practices

  • Default to DISP=SHR for read-only access whenever exclusive access is not actually required, to avoid unnecessarily blocking other jobs.
  • Always pair DISP=(NEW,CATLG,DELETE) style logic so failed steps clean up after themselves rather than leaving partial datasets behind.
  • Use SYSOUT=* rather than hardcoding a specific class, unless there is a specific reason output needs to be separated from the job's normal messages.
  • Keep in-stream DD * data short and clearly commented; anything large or reused across jobs belongs in a real dataset instead.

Frequently Asked Questions

The ddname is the symbolic name a program uses internally to refer to a file, matched by the DD statement's label. The DSN (dataset name) is the actual, real name of the dataset stored on the system. The DD statement is what links the two together for a given step.

Use OLD when a step needs exclusive access — most commonly when it will update or overwrite an existing dataset. Use SHR when a step only reads a dataset and there is no harm in other jobs reading it at the same time.

The allocation typically fails, because z/OS has no way to know how much storage to reserve for a brand-new dataset. Some installations set defaults through data class definitions, but it is best practice to specify SPACE= explicitly.

Yes, and most real steps do — one DD statement per file or dataset the program touches, plus commonly a SYSOUT DD for messages or reports and sometimes a SYSIN DD for in-stream control data.

Key Takeaways

  • A DD statement connects a program's internal ddname to a real dataset (or to SYSOUT, or to in-stream data).
  • DISP controls a dataset's status (NEW/OLD/SHR/MOD) and its disposition on normal and abnormal step completion.
  • SYSOUT= routes output to spooled print output by class, without needing a permanent dataset.
  • SPACE= and DCB= are required when a DD statement creates a brand-new dataset, describing size and record format.
  • DD * embeds small amounts of control data directly in the job stream, terminated by a /* line.

Summary

The DD statement is what makes JCL practically useful: it is the bridge between a program's internal file references and the real datasets, print output, or in-stream data those references should actually resolve to. Together, JOB, EXEC, and DD form the complete core of JCL. In the next lesson, you will learn how shops avoid rewriting the same JCL over and over by packaging common patterns into reusable procedures, or PROCs.

Next Lesson →

JCL Procedures (PROCs)