Ever since human beings started using computers, researches have been working to raise the abstraction level at which software engineers write programs. The first Fortran compiler was a major milestone in computer science because, for the first time, it let programmers specify what the machine should do rather than how it should do it. Since then, engineers have continued apace to raise programming abstraction levels. Today's object-oriented languages let programmers tackle problems of a complexity they never dreamed of in the early days of programming. Model-driven development(1,2) is a natural continuation of this trend. Instead of requiring developers to spell out every detail of a system's implementation using a programming language, it lets them model what functionality is needed and what overall architecture the system should have. Nowadays, compilers automatically handle issues such as object allocation, method lookup, and exception handling, which were programmed manually just a few years ago. By raising abstraction levels still further, MDD aims to automate many of the complex (but routine) programming tasks-such as providing support for system persistence, interoperability, and distribution-which still have to be done manually today. Because of MDD's potential to dramatically change the way we develop applications, companies are already working hard to deliver supporting technology. However, there is no universally accepted definition of precisely what MDD is and what support for it entails. In particular, many requirements for MDD support-where they've been identified-are still implicit. So, after reviewing the underlying motivations for MDD, this article sets out a concrete set of requirements that MDD infrastructures should support. It then analyzes the technical implications of these requirements and offers some basic principles by which they can be supported.