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

VBA Global Variable en Excel — variables Public, ámbito y por qué se reinician

|

VBA Global Variable en Excel — variables Public, ámbito y por qué se reinician

TL;DR — Pon Public gTaxRate As Double en la parte superior de un módulo estándar, por encima de todos los procedimientos, y cualquier procedimiento del libro podrá leerla y cambiarla. Esa es la mitad fácil. La mitad difícil es que una global solo recuerda su valor mientras el proyecto VBA siga cargado, y el proyecto se restablece más a menudo de lo que la gente cree: una instrucción End, el botón Restablecer, un error no controlado que el usuario finaliza, una edición en el editor de VBA, cerrar el libro. Tras un restablecimiento todas las globales vuelven a 0, "" o Nothing, sin ningún aviso. Así que nunca leas una global que no acabes de comprobar: accede a ella mediante una función que la reconstruya cuando esté vacía, y guarda en el propio libro todo lo que deba sobrevivir a la sesión.

' Module1 - en la parte superior, por encima de cualquier Sub o Function
Option Explicit
Public gTaxRate As Double            ' visible para todos los modulos de este proyecto

Sub SetUp()
    gTaxRate = 0.19
End Sub

Sub UseIt()
    Debug.Print gTaxRate             ' 0.19 - hasta que el proyecto se restablece, luego 0
End Sub

Este es el primero de una serie de tres artículos sobre dónde vive un valor. Toda variable tiene un ámbito, quién puede verla, y una duración, cuánto tiempo recuerda. Una global es la más amplia en ambas cosas: todo el proyecto, hasta que el proyecto se restablece. Una variable Static mantiene la duración larga pero reduce el ámbito a un solo procedimiento. Un parámetro Optional reduce las dos a una única llamada, y es el llamador quien lo entrega. Mi regla para toda la serie: elige la opción más estrecha que funcione.

Lo que aprenderás

  • El modelo mental: el ámbito es quién puede ver un valor; la duración, cuánto tiempo perdura
  • Cómo declarar una global, y Public frente a Global frente a Dim en la parte superior de un módulo
  • Qué reinicia una global y por qué el valor desaparece sin ningún error
  • La función de acceso autorreparable que vuelve inofensivo un restablecimiento
  • El Dim local que oculta tu global en silencio, y el error de nombre ambiguo
  • Variables Public en módulos de hoja, de ThisWorkbook y de UserForm
  • Cómo conservar un valor después de cerrar el libro

El modelo mental: ámbito y duración son dos preguntas distintas

El lugar donde declaras una variable responde a dos preguntas a la vez. El ámbito es quién puede verla. La duración es cuánto tiempo conserva su valor. VBA tiene tres niveles:

Dónde se declara Palabra clave Ámbito Duración
Dentro de un Sub o Function Dim solo ese procedimiento hasta que termina el procedimiento
Parte superior de un módulo Dim o Private todos los procedimientos de ese módulo hasta que el proyecto se restablece
Parte superior de un módulo estándar Public (o Global) todos los procedimientos del proyecto hasta que el proyecto se restablece

La guía de Dim cubre la primera fila. Este artículo trata de la última, y el dato clave está en la última columna: las variables de módulo y las públicas no viven hasta que cierras Excel, ni mueren cuando termina el procedimiento que las asignó. Viven exactamente lo mismo que el estado del proyecto, y ese estado es más frágil de lo que parece.

Declarar una global: Public, Global y dónde va la línea

Una global tiene que estar en la sección de declaraciones de un módulo estándar: después de Option Explicit y antes del primer procedimiento. Pon esa misma línea dentro de un Sub y VBA la rechaza, porque Public no está permitido dentro de un procedimiento.

Option Explicit

Public gUserName As String           ' en todo el proyecto
Global gRunCount As Long             ' lo mismo, palabra clave antigua
Private mCache As Object             ' solo en el modulo
Dim mLastRow As Long                 ' tambien solo en el modulo

Sub Demo()
    ' Public x As Long aqui seria un error de compilacion
End Sub

Global es la forma antigua de escribir Public. Solo funciona en módulos estándar y no aporta nada, así que usa Public. A nivel de módulo, Dim y Private significan lo mismo; prefiere Private, porque dice lo que quieres decir. Un prefijo como g para las globales y m para las variables de módulo no cuesta nada y evita el error de una sección posterior.

Si el valor nunca cambia, no es una variable en absoluto. Usa Public Const VAT_RATE As Double = 0.19, que, como muestra la guía de Const, no puede desviarse ni restablecerse.

La regla que muerde: una global solo vive lo que vive el proyecto

Este es el fallo con el que se topa todo el mundo. Una macro asigna gTaxRate en el primer clic, un segundo botón la usa y todo funciona durante la mañana. Después de comer, el segundo botón calcula con 0. Nada lanzó un error. Entre medias el proyecto se restableció, y un restablecimiento devuelve todas las variables de módulo y públicas a su valor vacío:

  • Se ejecuta una instrucción End en cualquier parte, que, como muestra la guía de End, borra todo el estado de golpe.
  • Pulsas Restablecer (el botón cuadrado) en el editor de VBA, o eliges Ejecutar > Restablecer.
  • Aparece un error en tiempo de ejecución no controlado y el usuario hace clic en Finalizar en el cuadro de diálogo.
  • Editas código en el editor de VBA: cambiar una declaración o añadir un módulo puede forzar una recompilación que restablece el proyecto. En modo de interrupción Excel pregunta antes; si no, simplemente ocurre.
  • Se cierra el libro que contiene el código.

Lo que no lo restablece: que el procedimiento que asignó el valor termine con normalidad, un error que captura tu propio controlador On Error, o Exit Sub. Esa asimetría es la razón por la que el error parece aleatorio. Aparece el día en que alguien se topa con un error no controlado, o en tu propio equipo justo después de editar el código.

La solución: accede a una global mediante una función autorreparable

No intentes evitar los restablecimientos; no puedes. Haz que sean inofensivos. Mantén la variable Private y expón una función que la reconstruya siempre que esté vacía:

Option Explicit
Private mRates As Object             ' Scripting.Dictionary, construido bajo demanda

Public Function Rates() As Object
    If mRates Is Nothing Then
        Dim r As Range
        Set mRates = CreateObject("Scripting.Dictionary")
        For Each r In ThisWorkbook.Worksheets("Rates").Range("A2:A50")
            If Len(r.Value) > 0 Then mRates(r.Value) = r.Offset(0, 1).Value
        Next r
    End If
    Set Rates = mRates
End Function

Sub PriceOrder()
    Debug.Print Rates()("EUR")       ' funciona tras cualquier restablecimiento - la funcion recarga
End Sub

Todos los llamadores piden Rates() en lugar de leer mRates directamente. Si un restablecimiento la vació, el primer llamador posterior paga el coste de recargarla y nadie ve una respuesta equivocada. La misma forma sirve para un valor simple: comprueba si es 0 o "" y recárgalo desde su origen. La guía de Dictionary cubre el propio objeto de caché.

La trampa silenciosa: un Dim local con el mismo nombre

El segundo error clásico no tiene ningún restablecimiento de por medio:

' Module1
Public gTotal As Double

Sub AddSales()
    Dim gTotal As Double             ' una NUEVA variable local que oculta la global
    gTotal = gTotal + 100            ' solo cambia la copia local
End Sub

Sub ShowTotal()
    MsgBox gTotal                    ' sigue en 0
End Sub

Un Dim a nivel de procedimiento con el mismo nombre que una global la oculta: dentro de AddSales, el nombre gTotal significa la variable local. VBA lo acepta sin quejarse, y Option Explicit no puede ayudar, porque las dos variables están declaradas. La solución es el hábito de nombres: las globales empiezan por g y nunca declaras con Dim un nombre con g dentro de un procedimiento.

La colisión contraria sí lanza un error. Si Module1 y Module2 declaran ambos Public Total, un tercer módulo que escriba Total recibe Ambiguous name detected («Se ha detectado un nombre ambiguo») en tiempo de compilación. Califícala como Module1.Total o, mejor, deja que cada global tenga un único propietario.

Public en un módulo de hoja, de ThisWorkbook o de UserForm

Public en la parte superior de un módulo de hoja, de ThisWorkbook o de un UserForm no crea una global. Crea una propiedad de ese objeto, así que los demás módulos tienen que nombrar el objeto para llegar a ella:

' En el modulo de codigo de Sheet1
Public Threshold As Double

' En Module1
Sub Check()
    Sheet1.Threshold = 500           ' calificada - esto funciona
    ' Threshold = 500                ' Variable not defined (con Option Explicit)
End Sub

Estos módulos son módulos de objeto, así que algunas cosas no se permiten ahí como miembros Public: matrices, constantes, cadenas de longitud fija y tipos definidos por el usuario provocan todos un error de compilación. Un UserForm añade una duración propia: UserForm1.SomeValue se pierde en el momento en que se descarga el formulario, como muestra la guía de UserForm con Unload Me frente a Me.Hide. Para una variable de verdad en todo el proyecto, usa un módulo estándar.

Conservar un valor después de cerrar el libro

Ninguna variable sobrevive al cierre del libro. Si un valor tiene que seguir ahí la semana que viene —la fecha de la última ejecución, una elección del usuario, un contador—, escríbelo en el archivo:

Sub RememberLastRun()
    ThisWorkbook.Worksheets("Settings").Range("B2").Value = Now
End Sub

Function LastRun() As Date
    LastRun = ThisWorkbook.Worksheets("Settings").Range("B2").Value
End Function

Una hoja de configuración muy oculta, como en la guía de Hide Sheet, la mantiene fuera de la vista. Un rango con nombre oculto también sirve. En ambos casos, el archivo es la memoria y la variable no es más que una copia rápida de él, que es la misma idea que la función de acceso de antes.

El criterio: globales para configuración y cachés, argumentos para los datos

Las globales no son malas; simplemente son compartidas, y el estado compartido es difícil de razonar. Cualquier procedimiento puede cambiar una global, así que cuando contiene un valor equivocado tienes que buscar en todo el proyecto quién lo escribió. Mi regla: usa una global para lo que todo el proyecto lee y casi nada escribe, como la configuración que se carga una vez y las cachés detrás de una función de acceso. Cuando un procedimiento necesita pasarle datos a otro, pásalos como argumento, eligiendo ByVal o ByRef a propósito. Si solo un procedimiento necesita recordar algo entre llamadas, una variable Static le da esa memoria sin compartirla.

Cómo ayuda ExcelMaster

Los errores de variables globales rara vez parecen errores de variables globales. Parecen un botón que funcionaba esta mañana y ahora calcula con cero, o un total que nunca cambia porque una copia local se quedó con la actualización.

ExcelMaster te deja describir lo que deben hacer las macros, por ejemplo «carga los tipos una vez y úsalos en todas las macros de precios». Escribe el estado compartido detrás de una función de acceso que sobrevive a los restablecimientos, mantiene los datos circulando por argumentos y encuentra el Dim local que está ocultando una global en el código existente.

Preguntas frecuentes

¿Cómo declaro una variable global en VBA?

Escribe Public seguido del nombre y el tipo, por ejemplo Public gTaxRate As Double, en la parte superior de un módulo estándar, antes del primer Sub o Function. A partir de ahí cualquier procedimiento del proyecto puede leerla y cambiarla. Declararla dentro de un procedimiento es un error de compilación.

¿Qué diferencia hay entre Public y Global en VBA?

Ninguna que importe. Global es la palabra clave antigua y solo funciona en módulos estándar; Public hace el mismo trabajo y además funciona en módulos de clase, de hoja y de UserForm. Usa Public.

¿Por qué mi variable global de VBA pierde su valor?

El proyecto VBA se restableció. Una instrucción End, el botón Restablecer del editor, un error no controlado en el que el usuario hace clic en Finalizar, algunas ediciones de código y cerrar el libro borran todas las variables de módulo y públicas. Accede al valor mediante una función que lo recargue cuando esté vacío.

¿Cómo conservo el valor de una variable después de cerrar el libro?

Guárdalo en el libro, no en una variable: una celda en una hoja de configuración oculta, un nombre definido oculto o una propiedad del documento. Vuelve a leerlo al abrir el libro, por ejemplo en el evento Workbook_Open.

¿Puede un UserForm usar una variable global?

Sí. Declara la variable como Public en un módulo estándar y el código del formulario podrá leerla y cambiarla. Una variable Public declarada dentro del propio módulo del UserForm pertenece al formulario y se pierde cuando este se descarga.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 01/10/2026.

Guías relacionadas: VBA Static Variable · VBA Optional Parameter · VBA Dim · VBA Const · VBA End · VBA ByRef frente a ByVal · VBA Dictionary · VBA Option Explicit