TL;DR —
CreateObject("ProgID")starts any COM app by name —Scripting.FileSystemObject,Outlook.Application,WScript.Shell. Because the object is named by a string, the compiler cannot check it: a wrong ProgID fails at runtime with error 429.CreateObjectalways starts a new instance (useGetObjectto attach to a running one), and anything you start you must release —.Quitthe app andSet obj = Nothing— or you leave a headless process running.
Sub CreateObjectDemo()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject") ' late binding: named by string
Debug.Print fso.FileExists("C:\data.txt")
Set fso = Nothing ' release what you created
End Sub
CreateObject is the verb that turns VBA from an Excel language into a Windows automation language. Give
it a ProgID — the registered name of a COM component — and it starts that component and hands you an
object you can drive: read files with Scripting.FileSystemObject, send mail with Outlook.Application,
run commands with WScript.Shell. It is the most powerful reach-outside-Excel tool in the language, and it
asks for the most care in return, because the compiler is switched off for whatever it gives you.
What you'll learn
- The mental model —
CreateObjectis a door keyed by a string (a ProgID), resolved at runtime - The real decision: late binding (
CreateObject) vs early binding (a reference +New) - Why
CreateObjectalways makes a new instance, and when to useGetObjectinstead - Why a headless
Outlook/Excelprocess is left running, and how to release it properly - What error 429 means and the handful of things that cause it
- When to prefer each style — develop early, ship late
The mental model: a door keyed by a string
Every automatable Windows component registers a ProgID — a text name like Scripting.Dictionary or
Word.Application. CreateObject takes that string, looks it up in the Windows registry at runtime,
starts the component, and returns a reference to it:
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary") ' registry lookup by name -> a live object
The important word is runtime. The object is named by a string, so nothing about it is known while you
type or when the project compiles — VBA finds out what dict is only when that line actually runs. That
single fact — an object identified by a string instead of a declared type — is what "late binding" means,
and it drives every trade-off and trap below.
Late binding vs early binding — the real decision
There are two ways to reach a COM object, and choosing between them is the heart of this topic.
Late binding is CreateObject with an Object variable. No reference, no declared type:
Dim ol As Object
Set ol = CreateObject("Outlook.Application") ' late: a string, an Object
Dim mail As Object
Set mail = ol.CreateItem(0) ' 0 = olMailItem — the constant name isn't available
Early binding is a checked reference (Tools → References → Microsoft Outlook Library) plus a declared
type and New:
Dim ol As New Outlook.Application ' early: a real type
Dim mail As Outlook.MailItem
Set mail = ol.CreateItem(olMailItem) ' named constants like olMailItem now exist
They compile to nearly the same thing; the difference is when the object is understood and what you get for it:
- Late (
CreateObject) — portable: no reference to set, survives version differences, ships to any machine that has the app. But no IntelliSense, named constants (olMailItem) do not exist so you hardcode their numbers or declare your ownConst, and every typo surfaces only when the line runs. - Early (
New+ reference) — IntelliSense as you type, the compiler catches misspelled members, and named constants work. But the reference is tied to a specific library version and can break on another machine or a different Office build.
The practical rule most professionals follow: develop with early binding for the IntelliSense and
compile checks, then switch to late binding to ship — change the Dim types to Object, replace New
with CreateObject, define any constants you used, and remove the reference. You get the comfortable
authoring experience and the portable deliverable.
CreateObject makes a new instance; GetObject attaches
CreateObject always starts a fresh instance of the component. For a stateless helper like the
FileSystemObject that is exactly right. For an application the user may already have open, it is a trap:
Set xl = CreateObject("Excel.Application") ' starts a SECOND, invisible Excel — even if one is open
Now there are two Excels, and the invisible one holds resources the user cannot see. When you mean the
one already running, use GetObject with no path and the ProgID:
Dim ol As Object
On Error Resume Next
Set ol = GetObject(, "Outlook.Application") ' attach to a running Outlook, if any
If ol Is Nothing Then Set ol = CreateObject("Outlook.Application") ' else start one
On Error GoTo 0
This "attach if running, otherwise start" pattern is the correct way to automate a user-facing app like
Outlook or Excel without spawning duplicates. GetObject has a second form too — GetObject(path) — which
opens a file's object directly (for example a workbook) without going through the application's Open
method. The distinction to hold: CreateObject = new, GetObject(, progID) = existing,
GetObject(path) = a file as an object.
Why Outlook stays open: release what you start
Here is the failure everyone hits once. You automate Outlook or a second Excel, the macro finishes, and a
OUTLOOK.EXE or EXCEL.EXE process keeps running in Task Manager with no window — invisible, holding
memory and sometimes a file lock. The cause: you started an application object and never told it to close.
An object you CreateObject does not go away when your variable goes out of scope if the app keeps itself
alive. You must quit the application and release the reference, ideally in cleanup that runs even on
error:
Dim ol As Object
On Error GoTo Cleanup
Set ol = CreateObject("Outlook.Application")
' ... use ol ...
Cleanup:
If Not ol Is Nothing Then
ol.Quit ' tell the app to close
Set ol = Nothing ' release the reference
End If
Two habits prevent the leak: call the app's .Quit (or .Close for a workbook/document) before you
finish, and Set obj = Nothing every object you created. Put both in an error handler — see
VBA error handling — so a mid-macro crash still cleans up. Lightweight objects like
Scripting.Dictionary or the FileSystemObject do not spawn a process and need no .Quit, but setting them
to Nothing is still tidy.
The error you'll hit: 429, at runtime
Because the ProgID is a string the compiler never checks, the classic CreateObject failure appears only
when the line runs: error 429, "ActiveX component can't create object." It has a short list of causes:
- A misspelled ProgID —
CreateObject("Scripting.FileSystemObjectt"). There is no compile-time spell-check for a string. - The application is not installed —
CreateObject("Outlook.Application")on a machine without Outlook. Late binding ships anywhere, but the target app must actually be present. - A bitness or registration problem — a 32-bit component on 64-bit Office, or a component that never registered correctly.
Because it is a runtime error, guard the call with error handling and give the user a clear message ("Outlook is not installed") instead of a raw 429. This runtime-only failure is the price of late binding, and the reason many developers author with early binding first: the compiler would have caught the typo.
The honest verdict: the gateway to Windows, with the compiler switched off
CreateObject is the single most capable reach-outside-Excel verb — the door to files, mail, the shell,
databases, and every other Office app. Its power and its danger are the same thing: an object named by a
string, unchecked until it runs. Four rules keep it safe:
- It is late binding by string → a ProgID resolved at runtime; a typo or a missing app fails with error 429 when the line runs, never at compile time.
- Choose late vs early deliberately → early (
New+ reference) for IntelliSense and compile checks while developing; late (CreateObject) to ship a portable file. CreateObjectis new;GetObjectis existing → use the "attach if running, else create" pattern for user-facing apps so you never spawn an invisible duplicate.- Release what you start →
.Quitthe app andSet obj = Nothing, in an error handler, or you leave a headless process holding memory and file locks.
Everything up to here lived inside Excel's own object model, where a call finishes before the next line and
a mistake raises a loud error. Shell, Environ, and CreateObject step outside that safety — and
CreateObject steps furthest, handing you an object the compiler never saw. Respect the four rules and it
is a gateway, not a minefield.
How ExcelMaster helps
The CreateObject bugs that cost real time are the invisible ones: a second headless Excel left running,
an Outlook process that never quit, a runtime 429 on a machine missing the app, a late-binding constant
hardcoded to the wrong number. Each comes from the compiler being switched off for objects named by a
string.
ExcelMaster writes the automation
glue correctly. Describe the job — "send this range as an Outlook email," or "read a text file with the
FileSystemObject" — and it produces the right binding (late, so it ships anywhere), attaches to a running
app with GetObject when that is what you mean, defines the constants late binding lacks, and cleans up
every object it started in an error handler. You describe which app to drive; it writes code that drives
it and leaves nothing hanging.
Frequently asked questions
What is the difference between CreateObject and New in VBA?
New (early binding) needs a checked reference to the component's library and a declared type —
Dim ol As New Outlook.Application — and gives you IntelliSense, compile-time checking, and named
constants. CreateObject("Outlook.Application") (late binding) names the component by a ProgID string,
needs no reference, and works across versions and machines, but has no IntelliSense and fails only at
runtime if the name is wrong. Develop with New for the tooling, ship with CreateObject for portability.
What is late binding vs early binding in VBA?
Early binding declares an object as a specific type (As Outlook.Application) backed by a Tools →
References entry, so the compiler knows the object and offers IntelliSense and named constants. Late
binding declares it as generic Object and creates it with CreateObject("ProgID"), so the object is
resolved by string at runtime with no compiler knowledge. Early binding is better for authoring; late
binding is better for shipping because it does not depend on a specific library reference being present.
How do I fix "ActiveX component can't create object" (error 429)?
Error 429 means CreateObject could not start the ProgID you passed. Check three things: the ProgID is
spelled correctly (Scripting.FileSystemObject, not a variant); the application is actually installed on
that machine (late binding ships anywhere but the target app must be present); and there is no bitness
mismatch (a 32-bit component under 64-bit Office). Wrap the call in error handling so users see a clear
message rather than the raw 429.
How do I use CreateObject with an already-open application?
CreateObject always starts a new instance, so for an app the user may already have open, use GetObject
instead: Set ol = GetObject(, "Outlook.Application") attaches to a running Outlook. The safe pattern is
"attach if running, otherwise create": try GetObject under On Error Resume Next, and if the object
Is Nothing, fall back to CreateObject. This avoids spawning a second, invisible copy of Excel, Outlook,
or Word.
Why does Excel or Outlook stay open after my macro finishes?
Because you created an application object and never released it. An automated app keeps its process alive
until you call .Quit and set the reference to Nothing. If the macro ends — or crashes — without doing
both, the EXCEL.EXE or OUTLOOK.EXE process lingers invisibly in Task Manager, holding memory and
sometimes a file lock. Always put obj.Quit : Set obj = Nothing in a cleanup section reached by an error
handler so it runs even when something fails.
Tested in
Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-08-30.
Related guides: VBA Shell · VBA Environ · VBA FileSystemObject · VBA Dictionary · VBA Outlook Automation
