TL;DR — A class module is a blueprint for your own object type. You write it once, then create as many independent instances as you like with
New. Two things catch everyone: the class module's name is the type name (there is noClasskeyword inside), and objects are reference types, soSet b = amakesaandbtwo names for the same instance. Prefer explicitSet x = New clsThingoverDim x As New clsThing, which hides a lazy-instantiation trap.
' --- In a class module named clsEmployee (rename it in the Properties window) ---
Private mName As String
Private mSalary As Currency
Public Property Get Name() As String: Name = mName: End Property
Public Property Let Name(v As String): mName = v: End Property
Public Property Get Salary() As Currency: Salary = mSalary: End Property
Public Property Let Salary(v As Currency): mSalary = v: End Property
Public Function AnnualCost() As Currency ' behaviour lives with the data
AnnualCost = mSalary * 1.3 ' salary + 30% overhead
End Function
' --- In a normal module ---
Sub Demo()
Dim e As clsEmployee
Set e = New clsEmployee ' create one instance
e.Name = "Sarah"
e.Salary = 65000
MsgBox e.Name & " costs " & e.AnnualCost ' 84500
End Sub
A Type bundles fields. A class module goes one step further:
it bundles fields and the code that acts on them, and gives you a real object you can
create, copy references to, and store in a Collection. This is
as close to object-oriented programming as VBA gets — and used well, it turns a sprawl
of loose variables and helper Subs into a handful of self-contained objects.
What you'll learn
- The mental model — a blueprint you stamp instances from
- Why there is no
Classkeyword (the module name is the type) - Creating instances —
Set ... = New, and theAs Newtrap - The rule that surprises people — objects share, they don't copy
- Setup and teardown —
Class_Initialize, and the missing constructor - When a class beats a Type or a Collection
The mental model: a blueprint, not the building
A class module is a blueprint; each New builds one instance from it. The
blueprint clsEmployee describes what every employee object has (a name, a salary)
and does (AnnualCost). It isn't itself an employee — it's the plan. Set e = New clsEmployee constructs one actual employee with its own data; do it three times and you
have three independent objects, each with its own name and salary, all built from the
same plan.
Hold on to that split. Almost every class-module confusion — "why is there no name in
the class?", "why did editing one object change another?" — dissolves once you separate
the blueprint (the class) from an instance (a New object).
Why there is no Class keyword
Coming from other languages, people open a class module and look for a line like
Class clsEmployee. There isn't one, and typing it is a compile error. In VBA, the
class module's name is the type name. You rename the object type by renaming the
module in the Properties window (F4), not with a keyword in the code.
So the workflow is: insert a class module, press F4, set (Name) to
clsEmployee (a cls prefix is the common convention), and start declaring its members
directly. The file is the class; its name is the type you write after As.
Creating instances: Set = New, and the As New trap
There are two ways to create an object, and they are not equivalent:
' Explicit (recommended)
Dim e As clsEmployee
Set e = New clsEmployee ' created exactly here, on this line
' Auto-instantiate (looks tidier, hides two traps)
Dim e As New clsEmployee ' NOT created yet — created on first use
The As New form is seductive because it's one line, but it hides two real problems:
- You can never test
If e Is Nothing. WithAs New, the moment you toucheto check it, VBA instantiates it — soIs Nothingis effectively alwaysFalse. You lose the ability to ask "was this ever created?" - It resurrects itself. Set an
As Newvariable toNothing, then reference it again, and VBA silently creates a new instance — a zombie object that reappears when you thought you had destroyed it.
Rule: prefer Dim e As clsEmployee + Set e = New clsEmployee. It creates the
object at a predictable line, and it keeps Is Nothing meaningful so you can guard
against uninitialised objects. And never forget the Set: writing e = New clsEmployee
without it raises error 91, "Object variable or With block variable not set" — the
same value-versus-object rule that says objects are assigned with
Set, not =.
The rule that surprises people: objects share, they don't copy
This is the mirror image of the Type article, and it's the deepest
source of class-module bugs. An object is a reference type. Set b = a does not
copy the object — it copies the reference, so a and b now point at the same
instance:
Dim a As clsEmployee, b As clsEmployee
Set a = New clsEmployee
a.Salary = 50000
Set b = a ' both names -> ONE instance
b.Salary = 70000 ' edits the shared object
Debug.Print a.Salary ' 70000 — a "changed by itself"
If you actually wanted two independent employees, Set b = a is a bug. VBA has no
automatic copy for objects; you write a Clone method that returns a fresh instance
with the same field values. And if what you really wanted was copy-on-assign in the
first place, that's your signal that a Type — a value type — was the
better model. Knowing which semantics you need, share or copy, is the whole reason
to understand both.
Setup and teardown: Class_Initialize and the missing constructor
A class can run code automatically when an instance is born or dies:
Private Sub Class_Initialize() ' runs on Set e = New clsEmployee
mSalary = 0 ' set defaults here
End Sub
Private Sub Class_Terminate() ' runs when the last reference goes away
' close files, release handles, etc.
End Sub
The catch: Class_Initialize takes no arguments. VBA has no parameterised
constructor — you cannot write New clsEmployee("Sarah", 65000). You create the
object first, then set its properties. Because that two-step dance is tedious and easy
to forget, the standard workaround is a small factory function in a normal module:
Function NewEmployee(nm As String, sal As Currency) As clsEmployee
Dim e As clsEmployee
Set e = New clsEmployee
e.Name = nm
e.Salary = sal
Set NewEmployee = e
End Function
' Set e = NewEmployee("Sarah", 65000) ' one readable line
My rule of thumb: any class you create more than once or twice deserves a factory
function. It gives you the parameterised constructor VBA left out, and it keeps creation
in one place instead of scattered Set + property lines.
When a class beats a Type or a Collection
Reach for a class module when at least one of these is true:
- Data and behaviour belong together — the record should validate, format, or compute things about itself, not have that logic scattered across helper Subs.
- You need many independent, self-managing objects — orders, invoices, employees —
ideally held in a
Collection, which accepts objects but not aType. - You want to hide internals — expose a clean surface through
properties and keep the backing fields
Private.
If none of those hold and you just want fields to travel together with cheap copies, a
Type is lighter and honest. Don't build a class for a bag of three values — but the
moment that bag needs to do something, a class is exactly right.
How ExcelMaster helps
Class modules are where "it compiles but behaves oddly" bugs live: the As New zombie,
the shared-reference edit that changes an object "by itself," the forgotten Set that
throws error 91. Each is invisible until it bites, and each comes from a rule that's
easy to state and easy to forget under deadline.
ExcelMaster lets
you describe the object you want — "an Employee with a name, a salary, and a method that
returns annual cost, that I can keep a list of" — and it writes the class with explicit
Set ... = New, a factory function, Private backing fields exposed through
properties, and a Collection to hold them. You get idiomatic, trap-free
object-oriented VBA without having to remember every way New and Set can surprise
you.
Frequently asked questions
What is a class module in VBA?
A class module is where you define your own object type — a blueprint that bundles data
(fields) and behaviour (methods and properties). Once defined, you
create independent instances of it with New. It's how VBA supports custom objects, one
step beyond a Type, which holds data only.
How do I create an instance of a class in VBA?
Declare a variable of the class type and assign a new instance with Set and New:
Dim e As clsEmployee then Set e = New clsEmployee. The Set keyword is required for
objects; omitting it (e = New clsEmployee) raises error 91. After creation, set its
properties: e.Name = "Sarah".
What is the difference between Dim As New and Set New in VBA?
Dim e As clsEmployee + Set e = New clsEmployee creates the object at that exact
line and keeps If e Is Nothing meaningful. Dim e As New clsEmployee defers creation
until first use, which makes Is Nothing always False and silently re-creates the
object if you set it to Nothing and touch it again. Prefer the explicit Set ... = New form.
Does a VBA class support a constructor with parameters?
No. The Class_Initialize event runs automatically when an instance is created but
takes no arguments, so you cannot write New clsEmployee("Sarah", 65000). The standard
workaround is a factory function in a normal module that creates the object, sets its
properties, and returns it — giving you a one-line, parameterised way to build the
object.
When should I use a class module instead of a Type or a Collection?
Use a class when the record needs behaviour (methods), when you want many independent
objects you can store in a Collection, or when you want to hide
internal fields behind properties. If you only need fields to
travel together with cheap, independent copies, a Type is lighter and
clearer.
Tested in
Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-08-04.
Related guides: VBA Type · VBA Property · VBA Dim · VBA Collection · VBA Dictionary
