We describe the metaprogramming framework currently used in Lean, an interactive theorem prover based on dependent type theory. This framework extends Lean's object language with an API to some of Lean's internal structures and procedures, and provides ways of reflecting object-level expressions into the metalanguage. We provide evidence to show that our implementation is performant, and that it provides a convenient and flexible way of writing not only small-scale interactive tactics, but also more substantial kinds of automation.bridge the gap between interactive use and automation. Lean implements a version of the Calculus of Inductive Constructions [Coquand and Huet 1988;Coquand and Paulin 1990], the details of which are described in Section 3. Its elaborator and unification algorithms are designed around the use of type classes, which support algebraic reasoning, programming abstractions, and other generally useful means of expression. Lean also has parallel compilation and checking of proofs, and provides a server mode that supports a continuous compilation and rich user interaction in editing environments such as Emacs and Visual Studio Code. It currently has a conditional term rewriter and several components commonly found in state-of-the-art Satisfiability Modulo Theories (SMT) solvers, such as forward chaining, congruence closure [Nelson and Oppen 1980], handling of associative and commutative operators, and E-matching [Detlefs et al. 2005].In Lean, definitions are compiled to bytecode that can then be evaluated in an efficient virtual machine. This is one sense in which Lean can be viewed as a programming language. (Native compilation is under development.) We obtain a metaprogramming language by exposing an API for procedures implemented natively in Lean's underlying C++ code base, thus taking us outside the axiomatic framework. Within a Lean source file, the keyword meta marks a clear distinction between definitions that make use of such extensions and those that are in the pure object language. Metadefinitions can also call themselves recursively, relaxing the termination restriction imposed by ordinary type theory. Otherwise, definitions and metadefinitions look very much the same, and can be written side-by-side in a Lean source file.There are a number of advantages to this approach. One is that users do not have to learn a new programming language to write metaprograms; they can work with the same constructs and notation used to define ordinary objects in the theorem prover's library. Another advantage is that everything in that library is available for metaprogramming purposes, including integers, lists, datatype constructors, records, and algebraic structures. Finally, metaprograms can be written and debugged in the same interactive environment, making it possible to develop the object library and supporting automation at the same time.A key application for metaprogramming is to implement tactics, which is to say, procedures which facilitate interactive theorem proving by carrying out straightf...