Schur factorization
Diagonalization A = X Lambda X^-1 is the dream, but not every matrix is diagonalizable, and even when it is, the basis X of eigenvectors can be wildly non-orthogonal and numerically dangerous to invert. The Schur factorization is the achievable, stable substitute: every square matrix A can be written A = Q T Q^*, where Q is unitary and T is upper triangular.
Read the trade carefully. You give up making the middle factor diagonal and settle for triangular, but in exchange the change-of-basis matrix Q is unitary, the gold standard for numerical work: its inverse is just Q^*, it preserves all norms, and it never amplifies error. Crucially, this exists for absolutely every square matrix, with no diagonalizability assumption at all.
The eigenvalues are not lost. Because T is triangular, its diagonal entries are exactly the eigenvalues of A, sitting right there to be read off. This is why Schur is the practical route to eigenvalues: production eigensolvers do not chase eigenvectors directly, they iterate the QR algorithm to converge A toward this triangular T while accumulating Q.
For real matrices with complex eigenvalues there is the real Schur form, where T is block upper triangular with 2x2 blocks on the diagonal carrying conjugate eigenvalue pairs, keeping all arithmetic real. When A is normal (A A^* = A^* A), T turns out to be exactly diagonal, recovering the unitary diagonalization of the spectral theorem.
A unitary Q and an upper-triangular T exist for every square A; the diagonal of T lists the eigenvalues.
Mantra: diagonalization is the theory, Schur is the practice. Whenever a textbook would diagonalize, a real eigensolver computes a Schur form instead.