TL;DR — Deja de codificar a mano
Range("A1:A100"). Tus datos crecen y encogen, así que encuentra su borde en tiempo de ejecución. La fórmula canónica esCells(Rows.Count, "A").End(xlUp).Row: simula pulsarCtrl+↑desde el fondo mismo de la columna. UsaRows.Count, nunca un65536codificado a mano. Hay cuatro maneras de preguntar «¿dónde terminan los datos?» y cada una responde a una pregunta ligeramente distinta:.End(xlUp)encuentra la última celda no vacía de una columna,.End(xlDown)se detiene en el primer hueco,.UsedRangeinforma de más y.Findes la única de verdad a prueba de huecos. Elige el método equivocado y procesarás las filas equivocadas, sin ningún error que te avise.
Encontrar la última fila es lo más habitual que una macro necesita hacer antes de
poder recorrer, copiar, ordenar o limpiar datos. Es también donde los principiantes
escriben la línea más frágil de todo el procedimiento: un A2:A500 codificado a
mano. Añade una fila y la macro se la salta; borra filas y procesa cientos de
celdas en blanco. El VBA de verdad nunca da por supuesto el tamaño de los datos: lo
mide.
Lo que aprenderás
- La fórmula canónica
Cells(Rows.Count, "A").End(xlUp).Row, descifrada pieza a pieza - Por qué
65536es una mina yRows.Countes la solución - El modo de fallo que se esconde en cada uno de los cuatro métodos (
.End(xlUp),.End(xlDown),.UsedRange,.Find) - Cómo encontrar la última columna, no solo la última fila
- Cuándo los huecos en tus datos te obligan a pasar de
.Enda.Find
El modelo mental: tus datos tienen un borde, y Excel no te lo entrega
Una hoja de cálculo es una cuadrícula de un millón de filas. Tus datos ocupan algún rectángulo dentro de ella, pero Excel no guarda una propiedad ordenada de «última fila» que puedas leer sin más. Así que tienes que caminar hasta el borde y preguntar dónde has aterrizado. Toda técnica fiable es alguna versión de «empieza en un punto que sabes que está más allá de los datos y luego salta de vuelta a lo último que hay de verdad».
La imagen mental de la fórmula canónica es una persona plantada en el fondo mismo
de una columna que pulsa Ctrl+↑: el cursor sube volando y se detiene en la última
celda con contenido. Eso es exactamente lo que hace .End(xlUp) en el código.
Sub FindLastRow()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Debug.Print "Last row with data in column A: " & lastRow
End Sub
Léela de dentro hacia fuera: ws.Rows.Count es el número de filas de la hoja
(1.048.576 en el Excel moderno). Cells(eso, "A") es la celda del fondo mismo de la
columna A. .End(xlUp) salta hacia arriba hasta la última celda no vacía. .Row
lee su número de fila. Esa única línea es el caballo de batalla, pero solo si
entiendes la trampa que lleva dentro.
La regla que te salva del peor error de última fila: nunca codifiques 65536 a mano
Durante una década, los tutoriales escribían Cells(65536, 1).End(xlUp).Row,
porque 65.536 era la última fila del antiguo formato .xls. Las hojas .xlsx
modernas tienen 1.048.576 filas. Si tus datos pasan de la fila 65.536 y arrancas
el salto hacia arriba desde la 65.536, empiezas por encima de una parte de tus
datos y devuelves en silencio una última fila demasiado pequeña, cortando el bucle
en mitad de la tabla.
' FRÁGIL — empieza por encima de cualquier dato que haya debajo de la fila 65536
lastRow = Cells(65536, 1).End(xlUp).Row
' CORRECTO — siempre empieza desde el verdadero fondo de ESTA hoja
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Rows.Count lee el número real de filas de la hoja en la que se ejecute el código,
así que está a prueba de futuro y de versiones. No hay ningún escenario en el que
codificar el número a mano sea mejor. Convierte Cells(Rows.Count, col) en un
reflejo.
La regla que ata cada método a su modo de fallo
Esta es la parte que todos los tutoriales se saltan: los cuatro métodos habituales no devuelven la misma respuesta, porque responden a preguntas distintas. Aprende el modo de fallo de cada uno y siempre sabrás cuál elegir.
.End(xlUp) — la última celda no vacía de una columna. La opción por defecto.
Su punto ciego es que solo mira una columna. Si eliges una columna con un hueco
donde la última fila queda vacía (pongamos que el nombre de la fila 500 está en
blanco, pero su importe no), te quedas corto. Elige una columna que tengas
garantizado que esté rellena en todas las filas de datos —un ID o una clave— o
encuentra la última fila de toda la tabla con .Find.
.End(xlDown) — el primer hueco desde arriba. Es Ctrl+↓ desde la fila 1.
No encuentra la última fila; encuentra la fila justo antes de la primera celda
en blanco. Una sola celda vacía en mitad de la columna te trunca al bloque
superior. No uses nunca .End(xlDown) para encontrar el final de los datos: solo
para encontrar el fondo de un tramo sin interrupciones.
' A1:A10 tiene datos, A6 está en blanco, A7:A10 tiene más datos
Cells(1, 1).End(xlDown).Row ' -> 5 (se detuvo en el hueco — INCORRECTO para «última fila»)
Cells(Rows.Count, 1).End(xlUp).Row ' -> 10 (última fila real — CORRECTO)
.UsedRange — el recuadro delimitador que Excel guarda en caché. ws.UsedRange
no son tus datos; son todas las celdas que Excel ha tocado alguna vez, incluidas
las que solo llevan formato, y no encoge cuando borras filas hasta que se guarda
o se recalcula el libro. Informa de más, así que un bucle sobre UsedRange puede
arrastrarse por cientos de filas fantasma. Además, no empieza necesariamente en la
fila 1 (mira las preguntas frecuentes). Trata UsedRange como «más o menos toda la
hoja», nunca como un número preciso de última fila.
.Find — el único método a prueba de huecos. Buscar hacia atrás la última celda
que contenga cualquier cosa, en cualquier sitio de la hoja es inmune a los blancos
internos y a la columna que elijas:
Function LastDataRow(ws As Worksheet) As Long
Dim c As Range
Set c = ws.Cells.Find(What:="*", After:=ws.Cells(1, 1), _
LookIn:=xlFormulas, SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious)
If c Is Nothing Then
LastDataRow = 0 ' hoja vacía
Else
LastDataRow = c.Row
End If
End Function
.Find es verboso y tienes que gestionar el caso Nothing (una hoja vacía), pero
es la respuesta correcta cuando tus datos tienen bordes irregulares o huecos
internos. LookIn:=xlFormulas encuentra celdas con una fórmula aunque ahora mismo
dé como resultado ""; xlValues las ignora, así que elige a conciencia.
El criterio de decisión: qué método y cuándo
- Lista limpia de una sola columna o tabla con una columna clave sólida →
Cells(Rows.Count, keyCol).End(xlUp).Row. Rápido, legible y correcto. - Datos con filas en blanco internas o un borde derecho irregular →
.Find(What:="*", SearchDirection:=xlPrevious). A prueba de huecos. - «Qué tamaño tiene, más o menos, todo lo que hay en esta hoja, para poder
limpiarla» →
.UsedRange. Informar de más es inofensivo cuando estás borrando. - Nunca uses
.End(xlDown)para la última fila, y nunca leasUsedRange.Rows.Countcomo si fuera el número de la última fila.
Encontrar también la última columna
El mismo truco del salto funciona en horizontal. Empieza en la celda del extremo
derecho de tu fila de encabezados y pulsa Ctrl+← desde el código:
Dim lastCol As Long
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
Con los dos números puedes construir el rango de datos exacto sin codificar nada a mano:
Dim rng As Range
Set rng = ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol))
De eso se trata todo: una vez que sabes encontrar los bordes, no vuelves a teclear
una dirección fija nunca más. Para construir un rango que se salte la fila de
encabezados, combina esto con Offset y Resize; para tomar
el bloque contiguo en una sola llamada, mira
UsedRange frente a CurrentRegion.
Cómo ayuda ExcelMaster
Casi toda pregunta del tipo «encontrar la última fila» es en realidad un paso hacia un objetivo mayor: recorrer esta columna y marcar duplicados, copiar filas nuevas a otra hoja, sumar por grupo. ExcelMaster toma ese objetivo en lenguaje natural —«por cada fila de la tabla de pedidos, copia las no terminadas a la hoja Pendientes»— y escribe por ti las cuentas del rango, encontrando los bordes de los datos de la forma robusta en lugar de dar por supuesto un tamaño fijo.
Seguirás escribiendo .End(xlUp) a mano dentro de una macro que se ejecuta de forma
programada. Pero para la tarea cotidiana de «procesa las filas que haya hoy»,
describir el resultado gana a acertar cada vez con Rows.Count y con el manejo de
huecos.
Preguntas frecuentes
¿Cuál es la mejor forma de encontrar la última fila en VBA?
Para una tabla con una columna clave que siempre esté rellena, usa
Cells(Rows.Count, keyColumn).End(xlUp).Row. Imita Ctrl+↑ desde el fondo de la
hoja y es rápido y legible. Si tus datos tienen filas en blanco internas o un borde
irregular, usa en su lugar Cells.Find(What:="*", SearchDirection:=xlPrevious).Row,
porque .End puede detenerse en un hueco.
¿Por qué debería usar Rows.Count en lugar de 65536?
65536 era la última fila del antiguo formato .xls. Las hojas .xlsx modernas
tienen 1.048.576 filas, así que arrancar el salto hacia arriba en la 65.536 empieza
por encima de cualquier dato que haya debajo de ese punto y devuelve una última
fila demasiado pequeña. Rows.Count siempre refleja el tamaño real de la hoja
actual.
¿Por qué UsedRange da una última fila incorrecta?
UsedRange es un recuadro delimitador en caché de todas las celdas que Excel ha
tocado alguna vez, incluidas las que solo tienen formato, y no encoge cuando borras
datos hasta que se guarda el archivo. Además, puede no empezar en la fila 1, así que
UsedRange.Rows.Count es un recuento, no el número de la última fila. Usa
.End(xlUp) o .Find para obtener una última fila precisa.
¿Cómo encuentro la última columna en VBA?
Refleja en horizontal la fórmula de la última fila:
Cells(1, Columns.Count).End(xlToLeft).Column. Salta desde la celda del extremo
derecho de la fila de encabezados de vuelta a la última columna con contenido.
¿Cómo encuentro la última fila cuando la columna tiene celdas en blanco?
.End(xlUp) solo inspecciona una columna, así que un blanco en la última fila de
datos de esa columna hace que se quede corto. O lo apuntas a una columna que esté
siempre rellena (un ID), o usas
Cells.Find(What:="*", SearchDirection:=xlPrevious).Row, que encuentra la última
celda con contenido en cualquier parte de la hoja sin importar los huecos.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 30/07/2026.
Guías relacionadas: VBA Offset · VBA UsedRange frente a CurrentRegion · VBA Range · VBA For Loop
