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

VBA Class Module in Excel — Build Your Own Object (Blueprint vs Instance, and the As New Trap)

|

VBA Class Module in Excel — Build Your Own Object (Blueprint vs Instance, and the As New Trap)

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 no Class keyword inside), and objects are reference types, so Set b = a makes a and b two names for the same instance. Prefer explicit Set x = New clsThing over Dim 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 Class keyword (the module name is the type)
  • Creating instances — Set ... = New, and the As New trap
  • 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. With As New, the moment you touch e to check it, VBA instantiates it — so Is Nothing is effectively always False. You lose the ability to ask "was this ever created?"
  • It resurrects itself. Set an As New variable to Nothing, 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 a Type.
  • 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