SAS Macro Language
A text-substitution macro and metaprogramming layer built into base SAS that generates SAS code dynamically before it is compiled and executed
Created by SAS Institute
The SAS Macro Language is a text-substitution and metaprogramming facility built into base SAS. It is not a separate product but a layer that sits above ordinary SAS code: rather than processing data directly, macro code writes SAS code, which the SAS system then compiles and executes. Where a DATA step manipulates rows and columns, the macro language manipulates the program text itself — substituting values, looping to generate repetitive statements, and conditionally including or excluding blocks of code. This makes it the primary tool SAS programmers reach for when they need to reduce duplication, parameterize routines, and build flexible, reusable, data-driven programs.
History & Origins
The macro facility grew out of the broader SAS system, which began as an academic statistical-computing project at North Carolina State University in the 1960s and was spun out as SAS Institute Inc. in 1976. As SAS programs grew larger and more repetitive, users needed a way to avoid writing the same code over and over with only small changes.
An early macro language was introduced in SAS 82 (around 1982), giving programmers their first ability to substitute text and generate code from within a SAS program. The facility matured substantially with SAS Version 5 in 1986, which shipped a complete macro language — the %MACRO/%MEND definition model, the %LET statement for creating macro variables, macro program-control statements, and the ampersand-and-percent syntax that SAS programmers still use today. Later releases extended its reach: Version 6.12 (released around 1997) added the %SYSFUNC function, which exposes nearly all DATA step functions to macro code and dramatically expanded what macros could compute at generation time.
Design Philosophy
The macro language is built on one deceptively simple idea: everything is text. A macro variable does not hold a number or a date in any typed sense — it holds a string. When SAS reads a program, a component called the macro processor runs first, resolving all macro references and triggering macro logic. Only the resulting plain SAS text is handed on to the SAS compiler. In other words, the macro language is a preprocessor: it operates at a phase before the “real” SAS program even exists.
This two-phase model is the source of both the macro language’s power and its notorious difficulty. Understanding when something resolves — at macro time versus at execution time — is the central skill (and the central trap) of macro programming. The payoff is that a programmer can capture a pattern once and let SAS mechanically generate the dozens or hundreds of nearly identical statements that pattern implies.
Key Features
| Feature | What it provides |
|---|---|
Macro variables (&name) | Named text values, referenced with a leading ampersand, substituted into code wherever they appear |
%LET | Creates and assigns macro variables |
%MACRO / %MEND | Defines a reusable, optionally parameterized macro program |
| Macro program control | %IF/%THEN/%ELSE, %DO/%END, and iterative %DO loops for generating code conditionally and repeatedly |
%GLOBAL / %LOCAL | Control the scope (symbol table) in which macro variables live |
| Automatic macro variables | System-supplied values such as &SYSDATE, &SYSVER, and &SYSLAST |
| Macro functions | Text functions like %SCAN, %SUBSTR, %UPCASE, and %SYSFUNC (which calls DATA step functions) |
| Autocall & stored compiled macros | Facilities for sharing macros across programs and storing pre-compiled macros for reuse |
PROC SQL ... INTO :var | A common bridge that reads values from data into macro variables, enabling data-driven generation |
A useful mental rule from the SAS community captures the whole model: macro variables are usually preceded by &, while macro statements and functions are usually preceded by %.
A Taste of the Language
The example below defines a parameterized macro that prints a summary for a chosen variable, then calls it twice. The macro processor generates two ordinary PROC MEANS steps before SAS ever runs them:
| |
Here &ds and &var are macro variables carrying the parameter values, and the two %summarize(...) calls cause the macro processor to emit two complete, slightly different PROC MEANS steps. A %do loop could just as easily generate one step per variable in a list.
Evolution
The macro language has evolved less in syntax than in reach. Its core constructs — %MACRO, %LET, macro variables, %IF/%DO — have been remarkably stable since Version 5 in 1986, which is precisely why decades-old macro code still runs on current SAS. What expanded over time was its connection to the rest of the system: %SYSFUNC (introduced with Version 6.12, around 1997) let macros tap the entire DATA step function library; autocall and stored-compiled-macro facilities made large shared macro libraries practical; and tight integration with PROC SQL made it straightforward to drive code generation directly from data. Through the SAS 9 platform (rollout around 2004), SAS 9.4 (2013), and the cloud-native SAS Viya (2016), the macro language has been carried forward essentially intact as a standard part of base SAS.
Current Relevance
Because the macro language is bundled with base SAS, it is wherever SAS is — and SAS remains entrenched in pharmaceuticals, banking, insurance, government, and other regulated industries. In those settings, macros are the everyday mechanism for standardization and reuse: a validated macro can be written once, reviewed, and then applied uniformly across hundreds of outputs, which is exactly the kind of repeatable, auditable process that regulated work demands. The macro facility continues to ship and be maintained in current releases, including SAS 9.4 Maintenance 9 (2025) and SAS Viya, ensuring that the enormous body of existing macro code keeps running on modern platforms.
Why It Matters
The SAS Macro Language is a clear, long-lived example of metaprogramming put to practical, industrial use. Long before “code that writes code” became a common talking point, working SAS programmers were using macros to compress repetitive analytics work, parameterize entire pipelines, and adapt programs to their data at run time. Its preprocessor model — resolve the macro text first, then compile and run the result — is conceptually simple yet powerful enough to underpin some of the most heavily validated, mission-critical reporting code in medicine and finance. For the analysts who maintain those systems, the macro language is not an optional add-on but the essential glue that makes large-scale, reusable SAS programming possible.
Timeline
Notable Uses & Legacy
Clinical trials & regulatory submissions
Pharmaceutical statistical programmers use macros to build reusable, validated routines that generate the many standardized tables, listings, and figures required for FDA submissions, parameterizing one macro across dozens of similar outputs
Banking & risk reporting
Financial institutions use the macro language to template repetitive regulatory and risk reports, looping a single macro over portfolios, time periods, or business units to generate consistent code at scale
Production data pipelines
Enterprises wrap recurring extract-transform-load and reporting jobs in macros so that the same logic can be re-run with different dates, libraries, or parameters without editing the underlying program
Reusable code libraries (autocall)
Organizations build shared autocall macro libraries — collections of general-purpose macros automatically available to every program — to standardize common tasks across analytics teams
Dynamic, data-driven programming
Analysts use macros together with PROC SQL's INTO clause to read values out of data at run time and feed them back into generated code, producing programs whose structure adapts to the data itself