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

VBA Static Variable en Excel — memoria que sobrevive a End Sub (y que recuerda demasiado)

|

VBA Static Variable en Excel — memoria que sobrevive a End Sub (y que recuerda demasiado)

TL;DR — Escribe Static en lugar de Dim dentro de un procedimiento y la variable conserva su valor cuando el procedimiento termina: Static clicks As Long cuenta todas las llamadas, no solo la actual. Es una memoria privada: nadie fuera del procedimiento puede verla, pero vive tanto como una global, hasta que el proyecto VBA se restablece. Esa es su fuerza y su trampa. Una Static nunca olvida por sí sola, así que también recuerda un indicador que se quedó atascado cuando un error se saltó la línea que lo limpiaba, y una caché construida con datos que han cambiado desde entonces. Usa Static cuando un solo procedimiento es dueño de la memoria; en cuanto otro procedimiento necesite leerla o restablecerla, pásala a un Private de módulo.

Sub CountClicks()
    Static clicks As Long            ' se conserva entre llamadas
    clicks = clicks + 1
    Application.StatusBar = "Clicked " & clicks & " times"
End Sub

Esta es la segunda parte de una serie de tres artículos sobre dónde vive un valor. Una variable global es visible para todo el proyecto y vive hasta que el proyecto se restablece. Una variable Static mantiene esa duración pero solo es visible para un procedimiento. Un parámetro Optional dura una sola llamada. La regla para las tres: elige el ámbito más estrecho que haga el trabajo.

Lo que aprenderás

  • El modelo mental: Static es ámbito local con duración de módulo
  • Static frente a Dim frente a un Private de módulo, lado a lado
  • Cuatro trabajos que Static hace bien: contadores, interruptores, protecciones contra reentrada, cachés
  • Las dos formas en que una Static recuerda demasiado: indicadores atascados y cachés caducadas
  • Por qué todas las celdas que llaman a una función de hoja comparten una sola Static
  • Static Sub, y cuándo sacar una Static de su procedimiento

El modelo mental: ámbito local, duración de módulo

Un Dim dentro de un procedimiento es un borrador: se crea cuando arranca el procedimiento y se tira cuando termina, así que la siguiente llamada empieza de cero. Un Static dentro de un procedimiento es un cajón del que solo este procedimiento tiene la llave. El procedimiento puede dejar algo dentro, terminar y encontrarlo ahí en la siguiente llamada.

Declaración Quién puede verla Cuánto conserva su valor
Dim n As Long dentro de un procedimiento ese procedimiento hasta que termina el procedimiento
Static n As Long dentro de un procedimiento ese procedimiento hasta que el proyecto se restablece
Private n As Long en la parte superior de un módulo todos los procedimientos del módulo hasta que el proyecto se restablece
Public n As Long en la parte superior de un módulo estándar todo el proyecto hasta que el proyecto se restablece

La segunda fila es la única que combina un ámbito estrecho con una vida larga. «Hasta que el proyecto se restablece» significa lo mismo que para una global: End, el botón Restablecer, un error no controlado que el usuario finaliza, algunas ediciones de código o cerrar el libro, todo ello cubierto en la guía de variables globales.

Declarar una Static, y el valor de la primera llamada

Static solo se permite dentro de un procedimiento, en lugar de Dim:

Function NextInvoiceNo() As Long
    Static lastNo As Long            ' 0 en la primerisima llamada
    lastNo = lastNo + 1
    NextInvoiceNo = lastNo
End Function

VBA no tiene inicializadores, así que Static lastNo As Long = 1000 es un error de sintaxis. En la primera llamada una Static contiene el valor vacío de su tipo, 0, "", Empty o Nothing, y el valor inicial real lo pones tú. Cuando 0 podría ser un valor legítimo, controla la primera llamada con una segunda Static:

Function NextInvoiceNo() As Long
    Static lastNo As Long, started As Boolean
    If Not started Then
        lastNo = ThisWorkbook.Worksheets("Settings").Range("B3").Value
        started = True
    End If
    lastNo = lastNo + 1
    NextInvoiceNo = lastNo
End Function

Fíjate en lo que reconoce esa versión: la Static es una copia rápida y el número real vive en el libro. Un contador que debe sobrevivir al cierre del archivo tiene que volver a escribirse ahí, porque ninguna variable sobrevive al proyecto.

Cuatro trabajos que Static hace bien

Un interruptor. Un botón que activa y desactiva algo necesita saber su último estado:

Sub ToggleGridlines()
    Static isOff As Boolean
    isOff = Not isOff
    ActiveWindow.DisplayGridlines = Not isOff
End Sub

Un contador o un total acumulado que pertenece a una sola rutina, como el número de factura de antes.

Una protección contra reentrada para un controlador de eventos que modifica la hoja que está vigilando. Escribir en una celda dentro de Worksheet_Change vuelve a disparar Worksheet_Change; un indicador Static corta el bucle:

Private Sub Worksheet_Change(ByVal Target As Range)
    Static busy As Boolean
    If busy Then Exit Sub
    busy = True
    On Error GoTo Done
    Target.Offset(0, 1).Value = Now  ' volveria a disparar este evento
Done:
    busy = False
End Sub

Una caché para una búsqueda que es lenta de construir y que solo necesita un procedimiento:

Function RegionOf(ByVal code As String) As String
    Static map As Object
    If map Is Nothing Then
        Dim r As Range
        Set map = CreateObject("Scripting.Dictionary")
        For Each r In ThisWorkbook.Worksheets("Regions").Range("A2:A500")
            map(r.Value) = r.Offset(0, 1).Value
        Next r
    End If
    If map.Exists(code) Then RegionOf = map(code)
End Function

La comprobación If map Is Nothing cumple una doble función: construye la caché en la primera llamada y la reconstruye después de que un restablecimiento del proyecto la haya vaciado. Es el patrón autorreparable de la guía de variables globales, con la caché privada de la única función que la usa.

La regla que muerde: una Static nunca olvida por sí sola

Todos los errores con Static son el mismo error: el valor sobrevivió a la situación en la que era válido.

El indicador atascado. Toma la protección contra reentrada de antes y borra la línea On Error GoTo Done. Ahora cualquier error después de busy = True, una celda protegida o una falta de coincidencia de tipos, termina el controlador antes de que se ejecute busy = False. El indicador se queda en True y, a partir de ahí, la primera línea sale siempre: el controlador de eventos está muerto en silencio hasta que el proyecto se restablece. El usuario ve una hoja que dejó de actualizarse, sin ningún mensaje de error. Un indicador de protección debe limpiarse en todas las rutas de salida, y por eso el controlador de errores salta a la línea que lo limpia. La guía de EnableEvents cubre la otra protección habitual, con la misma regla.

La caché caducada. RegionOf construye su mapa una sola vez. Si después alguien añade una región a la hoja, la función sigue respondiendo con el mapa antiguo durante todo el día, porque nada le dice que los datos cambiaron. Y nada fuera de la función puede decírselo, porque la Static es invisible desde fuera. Ese es el verdadero límite de Static: no puedes restablecerla desde otro procedimiento.

La sorpresa de las UDF: todas las celdas comparten una sola Static

Una Static pertenece al procedimiento, no al lugar desde el que se llamó. En una función de hoja eso significa que todas las celdas que la llaman comparten una sola variable:

Function CallCount() As Long
    Static n As Long
    n = n + 1
    CallCount = n
End Function
' =CallCount() en A1, A2 y A3 no da 1, 1, 1 -
' da tres numeros distintos, en el orden de calculo

Excel decide el orden de cálculo y puede recalcular cualquier celda en cualquier momento, así que una función definida por el usuario (UDF) cuya respuesta depende de una Static da resultados que cambian solos. La guía de Function explica por qué una función de hoja debe depender solo de sus argumentos. Una caché Static dentro de una UDF, como el mapa de RegionOf, está bien, porque cambia lo rápido que llega la respuesta y no cuál es. Un contador Static o un total acumulado dentro de una UDF es un error.

Static Sub, y Static en un UserForm

Poner Static delante del procedimiento convierte en estáticas todas sus variables locales:

Static Sub Tally()
    Dim total As Double              ' tambien estatica, por el Static Sub
    total = total + 1
End Sub

Existe, pero evítalo. Quien lee ve Dim y da por hecho una variable nueva, y la única palabra clave de arriba que dice lo contrario es fácil de pasar por alto. Marca una a una las variables que necesitan memoria.

Las variables Static en los procedimientos de un UserForm solo duran mientras el formulario siga cargado. Después de Unload, el siguiente Show empieza con valores nuevos, la misma duración que las demás variables del formulario en la guía de UserForm.

El criterio: Static hasta que un segundo procedimiento la necesite

Static es la forma más estrecha de dar memoria a un procedimiento, y estrecho es bueno: nada más puede cambiar el valor por accidente, y la declaración está justo al lado del código que la usa. Mi regla: usa Static cuando exactamente un procedimiento lee y escribe la memoria y nada más necesita nunca limpiarla. En cuanto un segundo procedimiento tenga que verla, o necesites un botón de «actualizar» que vacíe una caché, pasa la variable a la parte superior del módulo como Private y añade un pequeño procedimiento que la restablezca:

Private mMap As Object

Sub ResetRegionCache()
    Set mMap = Nothing               ' la siguiente busqueda la reconstruye
End Sub

Así el ámbito se mantiene tan estrecho como permite la nueva necesidad, y evitas saltar directamente a una global Public.

Cómo ayuda ExcelMaster

Los errores con Static parecen fantasmas: un controlador de eventos que deja de dispararse sin motivo visible, una búsqueda que ignora la fila que acabas de añadir, una UDF cuyos números cambian cada vez que la hoja se recalcula.

ExcelMaster te deja describir lo que debe recordar la macro, por ejemplo «numera cada factura nueva a partir de la última usada». Elige el lugar adecuado para esa memoria —una Static, una variable de módulo con restablecimiento o una celda del libro— y añade el control de errores que impide que un indicador de protección se quede atascado.

Preguntas frecuentes

¿Qué significa Static en VBA?

Static declara una variable dentro de un procedimiento que conserva su valor cuando el procedimiento termina. La siguiente llamada ve el valor que dejó la anterior. Solo ese procedimiento puede ver la variable, y el valor se pierde cuando el proyecto VBA se restablece o se cierra el libro.

¿Qué diferencia hay entre Static y Dim en VBA?

Una variable Dim dentro de un procedimiento empieza vacía en cada llamada y desaparece cuando el procedimiento termina. Una variable Static solo empieza vacía en la primera llamada y conserva su valor entre llamadas. Ambas son visibles únicamente dentro de su procedimiento.

¿Cómo conservo el valor de una variable entre ejecuciones de una macro?

Declárala con Static dentro del procedimiento si solo ese procedimiento la necesita, o como Private en la parte superior del módulo si la necesitan varios. Las dos conservan el valor hasta que el proyecto se restablece. Para conservarlo después de cerrar el libro, guárdalo en una celda o en un nombre definido.

¿Puedo dar un valor inicial a una variable Static?

No en la declaración: VBA no tiene inicializadores, así que Static n As Long = 5 es un error de sintaxis. La variable empieza como 0, "", Empty o Nothing. Asigna un valor inicial en la primera llamada, usando una segunda Static de tipo Boolean para saber si la primera llamada ya se produjo.

¿Cómo restablezco una variable Static?

Solo el procedimiento que la declara puede cambiarla, así que dale a ese procedimiento una forma de restablecerla, o pasa la variable a nivel de módulo como Private y añade un pequeño procedimiento de restablecimiento. Restablecer todo el proyecto VBA también la vacía, junto con todas las demás variables de módulo y públicas.

Probado en

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

Guías relacionadas: VBA Global Variable · VBA Optional Parameter · VBA Dim · VBA Function · VBA Worksheet Change · VBA EnableEvents · VBA Dictionary · VBA UserForm