🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Application.Run in Excel — Call a Macro by Its Name

|

VBA Application.Run in Excel — Call a Macro by Its Name

TL;DR — Application.Run "MacroName", arg1, arg2 runs a macro you name with a string, so the code decides which macro to run while it is running, not when you write it. Use it as a statement (no parentheses) or capture a Function's return with x = Application.Run("MyFunc", 5). The catch: the name is text, so a typo is a run-time error 1004, not a red squiggle at compile time. Reach for it when the macro name is not known until runtime — a dispatch table, a name in a cell, a plugin. If you already know the macro, just call it directly.

Sub RunByName()
    ' Decide the macro name at runtime, then run it
    Dim macroName As String
    macroName = Range("Config!B2").Value        ' e.g. "BuildMonthlyReport"
    Application.Run macroName, Date, "Finance"   ' pass arguments by position
End Sub

Most of the time you call a macro the obvious way: you type its name, BuildReport, and it runs. That only works because you know the name when you write the code. Application.Run is for the other case — when the name lives in a cell, a settings sheet, or a variable, and you do not know it until the macro is already running. This is the first of three tools that share one idea, so it is worth stating that idea up front: Application.Run, CallByName and Evaluate all turn a string into an executed action at runtime. Run executes a macro named by a string, CallByName invokes an object member named by a string, and Evaluate computes an Excel expression held as text. The power is indirection; the price is that you give up the compiler, so a typo becomes a run-time error instead of a squiggly line. The rule that governs all three: never hand them a string you did not build or check yourself.

What you'll learn

  • The mental model that ties Application.Run, CallByName and Evaluate together
  • The statement form versus capturing a Function's return value
  • Passing arguments by position — up to 30, and why objects arrive as values
  • Running a macro that lives in another open workbook
  • Why a mistyped name fails at run time, not compile time, and how to guard it
  • The one situation that actually justifies Application.Run: a dispatch table

The mental model: a switchboard that looks up the macro by name

Think of a switchboard operator. A direct call, BuildReport, is a private line wired straight to one office — fast, but fixed forever. Application.Run is the operator: you say a name out loud and they connect you to whoever that name points to right now. The name can come from anywhere — a cell, a config sheet, a loop over a list — because the connection is made at runtime, not soldered in when you write the code.

BuildReport                        ' direct call: name fixed at write time
Application.Run "BuildReport"      ' indirect call: name resolved at run time

Those two lines do the same thing today. The difference only shows up when the name is not a constant. The moment you write Application.Run someVariable, you have bought yourself indirection — and taken on the responsibility for making sure someVariable holds a real macro name. That trade is the whole topic.

The syntax: statement form vs capturing a return value

Like MsgBox, Application.Run has two shapes, and the brackets decide which one you get. As a statement, drop the parentheses:

Application.Run "FormatSheet", ActiveSheet.Name   ' run a Sub, ignore any result

To capture what a Function returns, wrap the whole call in parentheses and assign it:

Dim total As Double
total = Application.Run("SumColumn", "B")          ' capture the Function's return value

The rule is the same one that trips people with MsgBox: parentheses mean this is an expression whose value I want. Use the statement form for a Sub; use the function form for a Function whose result you need.

Passing arguments — by position, up to 30, as values

You pass arguments after the name, separated by commas. Two hard limits are worth memorising:

Application.Run "PostEntry", 2026, "March", 4820.5   ' args go by POSITION, not by name

First, arguments are positional only — you cannot use named:= arguments here, so the order in your call has to match the order in the target macro's signature exactly. Second, there is a ceiling of 30 arguments, which in practice means: if you are approaching it, pass an array or a Dictionary instead of a long argument list.

One quiet surprise: objects are passed as values, not as live references. If you pass a Range, the target receives its .Value, not the range itself. When a macro needs to act on a real object, put the name in the string and let the target resolve the object itself, rather than trying to hand the object across Application.Run.

Running a macro in another open workbook

This is where Application.Run earns regular use: calling a macro that lives in a different workbook — a shared add-in, a tool workbook, a report template. Qualify the name with the workbook:

Application.Run "'Monthly Tools.xlsm'!Module1.RefreshData"

Three details decide whether this works. The workbook must be open — Application.Run will not open it for you. Wrap the workbook name in single quotes if it contains spaces ('Monthly Tools.xlsm'). And the target macro must be Public (the default for a Sub in a standard module); a Private macro is invisible from outside its own module. Get any of the three wrong and you land on the same error the next section is about.

The trap: the name is a string, so a typo is a run-time error

Here is the cost of indirection, and the single most important line on this page. When you call a macro directly and misspell it, the VBA compiler stops you before anything runs. When you misspell the string in Application.Run, the compiler has nothing to check — it is just text — so the mistake surfaces only when that line executes, as run-time error 1004, "Cannot run the macro":

Sub SafeRun(macroName As String)
    On Error GoTo NotFound
    Application.Run macroName
    Exit Sub
NotFound:
    MsgBox "Macro not found or failed: " & macroName, vbExclamation
End Sub

Because the compiler cannot help you, you have to. Any time the macro name comes from outside your code — a cell, a file, user input — wrap the call in On Error handling and treat "macro not found" as a normal outcome, not a crash. A string-driven call without an error guard is a bug waiting for the first typo in a config sheet.

When Application.Run actually earns its place: a dispatch table

If you know the macro at write time, call it directly — Application.Run "BuildReport" is slower to read and easier to break than BuildReport. The method pays off only when the name is genuinely dynamic. The cleanest example is a dispatch table: map a set of names to a set of actions, then run whichever one the situation calls for.

Sub RunAction(actionName As String)
    ' A whole Select Case collapses into one line:
    ' the button's Tag, a cell, or a config row decides which macro runs.
    Application.Run "Actions." & actionName     ' "Actions.Export", "Actions.Refresh", ...
End Sub

That single line replaces a growing Select Case that you would otherwise have to edit every time you add an action. It is the pattern behind plugin architectures, ribbon buttons that carry their handler name in a Tag, and macros whose behaviour is driven by a settings sheet. The test for whether you should use Application.Run is simple: is the name a constant? If yes, call directly. If no, this is the tool.

Application.Run vs a direct call vs CallByName

Three ways to invoke code, three jobs. A direct call is for a macro you know by name at write time — always prefer it when you can. Application.Run is for a macro whose name is a string decided at run time, including one in another workbook. CallByName is the same idea aimed at an object's property or method rather than a standalone macro. If you find yourself building a string to reach a member of a specific object (a control, a shape, a class), that is CallByName's job, not Run's.

How ExcelMaster helps

The failure on this page is silent by design: a name that is right today and wrong the moment someone edits a config sheet, surfacing as error 1004 deep in a run. Guarding every string-driven call, quoting workbook names, checking that a target is Public — it is easy to get one of them wrong.

ExcelMaster lets you describe the goal in plain words — "run the macro named in this cell, and tell me clearly if it does not exist" — and it writes the Application.Run code with the error guard, the workbook qualifier, and the return handling already in place. You keep the workbook and the code, and you skip the 1004.

Frequently asked questions

How do I run a macro by its name as a string in VBA?

Use Application.Run "MacroName". As a statement you omit the parentheses; to capture a Function's result, write x = Application.Run("MyFunc", arg). Because the name is a string the compiler cannot check it, so wrap the call in On Error handling — a typo shows up as run-time error 1004 rather than a compile error.

How do I pass arguments to a macro with Application.Run?

List them after the name, separated by commas: Application.Run "PostEntry", 2026, "March". Arguments are positional only — you cannot use named:= syntax — and there is a limit of 30. Objects are passed as values (a Range arrives as its .Value), so for anything larger pass an array or a Dictionary.

How do I run a macro in another workbook?

Qualify the name with the workbook: Application.Run "'Tools.xlsm'!Module1.RefreshData". The other workbook must already be open, use single quotes around its name if it contains spaces, and the target macro must be Public. Application.Run does not open the workbook for you.

Why does Application.Run give error 1004, cannot run the macro?

Almost always the name string does not resolve to a runnable macro: it is misspelled, the workbook that holds it is not open, or the macro is Private. Because the name is text, this can only be caught at run time. Check the spelling, confirm the workbook is open, and make sure the target is Public.

When should I use Application.Run instead of just calling the macro?

Only when the name is not known until run time — it comes from a cell, a config sheet, a variable, or a loop, or the macro lives in another workbook. If you know the macro name as you write the code, call it directly: BuildReport is clearer and the compiler will catch typos. For invoking a member of an object by name, use CallByName instead.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-27.

Related guides: VBA CallByName · VBA Evaluate · VBA Sub · VBA Function · VBA On Error · VBA Select Case · VBA Dictionary