A Full Overview of JVM Programming Languages
The Java Virtual Machine was originally created to run Java, a language designed by Sun Microsystems in the mid-1990s with portability as its central promise. The slogan “write once, run anywhere” captured the ambition behind the JVM architecture, which compiled source code into bytecode that any machine with a compatible runtime could execute. This design decision, made decades ago, turned out to be one of the most consequential in software history.
As the JVM matured and proved itself as a reliable, high-performance execution environment, language designers began to recognize that its bytecode format was not inherently tied to Java syntax. Any language that could compile down to valid JVM bytecode could run on the same runtime, benefit from the same garbage collection, access the same mature standard library, and interoperate with the enormous existing ecosystem of Java libraries. This realization opened the door to a generation of JVM languages that each brought new ideas to the platform while standing on the shoulders of decades of Java engineering.
Kotlin is today one of the most prominent JVM languages outside of Java itself, developed by JetBrains and first released in 2011. It was designed to be fully interoperable with Java while addressing many of the complaints developers had accumulated about Java’s verbosity and lack of modern language features. Kotlin code compiles to JVM bytecode and can call Java libraries directly, making it practical to adopt incrementally within existing Java projects.
The language gained enormous mainstream visibility when Google announced it as a first-class language for Android development in 2017. Since then, it has grown well beyond Android, finding strong adoption in server-side development through frameworks like Ktor and Spring Boot with Kotlin support. Its features include null safety built into the type system, extension functions, coroutines for asynchronous programming, data classes that eliminate boilerplate, and a concise syntax that typically requires far fewer lines of code than equivalent Java to express the same logic.
Scala is a statically typed language that blends object-oriented and functional programming into a single unified system, running on the JVM and designed by Martin Odersky at EPFL in Switzerland. It compiles to JVM bytecode and interoperates fully with Java libraries, but its syntax and type system are substantially more expressive and complex than Java’s. Scala was built around the idea that a better language design could combine the familiar class-based structure of object-oriented code with the composability and correctness guarantees of functional programming.
The language became widely known through Apache Spark, the distributed data processing framework written primarily in Scala, which brought the language to the attention of data engineers worldwide. Scala’s type system includes features like type inference, algebraic data types, pattern matching, implicits, and higher-kinded types that allow library authors to build expressive, safe APIs. The learning curve is steeper than most JVM languages, but organizations that invest in Scala typically cite its ability to catch errors at compile time and express complex domain logic concisely as its primary advantages.
Groovy is a dynamically typed language for the JVM that was designed to feel familiar to Java developers while offering a more expressive and flexible syntax. It supports optional typing, meaning developers can choose between dynamic and static type checking depending on the situation, and it compiles to JVM bytecode just like Java and Kotlin. Groovy code can directly call Java APIs and Java code can call Groovy classes without any bridging layer.
The language became widely adopted through its role as the scripting language for Gradle, the build automation tool that is now the standard for Android and many Java projects. Groovy’s support for closures, metaprogramming, and domain-specific language construction made it particularly well suited to configuration and build scripting contexts. The Grails web framework, which is built on top of Groovy, brought convention-over-configuration web development to the JVM ecosystem in a style reminiscent of Ruby on Rails.
Clojure is a modern dialect of Lisp that runs on the JVM, created by Rich Hickey and first released in 2007. It is a dynamically typed, functional language with immutable data structures at its core and a strong emphasis on simplicity and the management of program state. Clojure treats code as data through its homoiconic syntax, where programs are written using the same data structures the language manipulates at runtime, enabling powerful macro-based metaprogramming.
The language has a passionate and devoted community, particularly in domains like financial services, data analysis, and web development. Its persistent data structures, which allow efficient structural sharing between old and new versions of a collection, make concurrent programming significantly safer by eliminating shared mutable state. ClojureScript, a variant that compiles to JavaScript, extends the language’s reach to the browser, while the core JVM version gives full access to the rich Java library ecosystem.
Ceylon was a statically typed language for the JVM developed by Red Hat, led by Gavin King who was also known for creating the Hibernate ORM framework. Its design emphasized readability, modularity, and a clean, well-specified type system that avoided some of the historical inconsistencies present in Java. Ceylon included union and intersection types, a module system built into the language itself rather than layered on top, and a readable syntax that borrowed some ideas from Java while cleaning up awkward corners.
The language never reached mainstream adoption and was officially retired in 2020 after the Eclipse Foundation transferred stewardship without sufficient community energy to sustain it. Despite its relatively short life, Ceylon represented an interesting design experiment in building a JVM language from first principles with modularity as a primary concern. Its influence on language design thinking is more lasting than its user base, and some of its ideas about type systems and module boundaries found their way into discussions about the direction of Java itself.
JRuby is an implementation of the Ruby programming language that runs on the Java Virtual Machine, allowing Ruby code to execute with JVM performance characteristics and access the full ecosystem of Java libraries. It was created to give Ruby developers the option of running on the JVM when Java integration, performance, or deployment environment requirements made that beneficial. JRuby supports nearly all of the Ruby standard library and most popular Ruby gems.
The practical value of JRuby lies in interoperability. Teams that have substantial Ruby codebases but also rely on Java libraries can use JRuby as a bridge, calling Java code directly from Ruby scripts and vice versa. JRuby also benefits from JVM performance optimizations like just-in-time compilation, which can make certain Ruby workloads run faster than they would under the standard MRI Ruby interpreter. However, startup time and memory footprint are typically higher on the JVM, which makes JRuby less suitable for short-lived scripts compared to traditional Ruby.
Jython is an implementation of Python that runs on the JVM, providing Python developers with access to Java libraries and allowing Java projects to embed Python scripting capabilities. It supports Python 2 syntax and semantics, though Python 3 support has been a long-standing and incomplete work in progress that has limited its adoption in more recent years. Jython compiles Python code to JVM bytecode, meaning Python programs run under the same runtime as Java applications.
The primary use case for Jython has been embedding Python as a scripting language within Java applications, giving end users the ability to write automation scripts in Python that interact with the application’s Java objects directly. Enterprise software vendors have used Jython to expose scripting interfaces without requiring users to learn Java. However, the Python 3 gap has made Jython increasingly difficult to recommend for new projects, and alternative approaches like GraalVM’s Python support have begun to offer more modern options for Python on the JVM.
Frege is a purely functional programming language for the JVM inspired by Haskell, designed to bring Haskell-style type classes, monads, and lazy evaluation to the Java platform. It compiles to Java source code rather than directly to bytecode, which then gets compiled normally by the Java compiler. This unusual compilation strategy means Frege programs can interoperate with existing Java code through generated Java interfaces and classes.
The language occupies a very niche position in the JVM ecosystem, appealing primarily to developers who want Haskell-like semantics but need to target the JVM for deployment or interoperability reasons. Its strong type system and purity guarantees make it theoretically compelling for building highly reliable software, but the small community and limited tooling make it impractical for most professional projects. Frege is better understood as a research and learning platform than as a production-grade alternative to mainstream JVM languages.
Xtend is a statically typed language for the JVM developed by the Eclipse Foundation, designed to be a cleaner and more expressive version of Java while compiling transparently to readable Java source code rather than directly to bytecode. This compile-to-Java approach is unusual and means that Xtend code is always paired with its Java equivalent, making debugging and tool integration more familiar for Java developers. Xtend supports features like extension methods, lambda expressions that predate their addition to Java, and a powerful template expression syntax.
The language was adopted in several Eclipse ecosystem projects and found particular use in code generation tooling and domain-specific language development through the Xtext framework. Because Xtend compiles to Java, the resulting code can be inspected, debugged, and maintained by any Java developer, which lowers the risk of adopting the language in teams where not everyone knows Xtend. However, the language has not grown significantly beyond its Eclipse ecosystem roots, and its most compelling features have gradually appeared in Java itself through newer language versions.
Eta is a dialect of Haskell that compiles to JVM bytecode and aims to be compatible with a large subset of the GHC Haskell ecosystem. It was developed to allow Haskell developers to access the Java library ecosystem and deploy on the JVM while retaining the full expressive power of Haskell’s type system, lazy evaluation, and functional programming model. Eta can call Java methods directly through its foreign function interface, making Java libraries accessible from Haskell-style code.
The project gained attention from developers who wanted the correctness guarantees of Haskell in environments where JVM deployment was mandatory. Eta’s ability to use Haskell packages from Hackage, the Haskell package repository, means developers can bring a wide range of existing functional libraries to JVM projects. Like other niche JVM languages, Eta faces challenges around tooling maturity and community size, but it represents one of the more technically ambitious attempts to bring a purely functional type system to the Java platform.
Fantom is a statically typed, object-oriented language designed to run on multiple platforms including the JVM, the .NET runtime, and JavaScript environments. Created by Brian and Andy Frank, Fantom was built around the idea of writing code once and targeting multiple runtimes without modification. Its type system avoids some of the complexity of Java while providing features like closures, nullable types, and a clean pod-based module system.
Fantom never achieved significant mainstream adoption but remains an interesting example of a language designed for genuine cross-runtime portability. Its approach to nullable types and its avoidance of checked exceptions addressed two persistent frustrations Java developers commonly expressed. The language has a small but active community and continues to be maintained, primarily used in projects where its cross-platform targeting capability provides a specific practical advantage that single-runtime languages cannot offer.
Red is a language inspired by Rebol that can compile to native code as well as run in interpreted mode, and its JVM-targeting variant brings its unique data-centric programming model to the Java ecosystem. Red was designed to be a full-stack language capable of handling everything from low-level system tasks to high-level scripting within a single compact toolchain. Its syntax is minimal and homoiconic, sharing design DNA with Lisp and Rebol.
The JVM connection for Red is less central than for languages like Kotlin or Scala, as Red’s primary identity involves native compilation and a self-contained toolchain rather than JVM interoperability. However, its data-oriented design philosophy offers an interesting contrast to the class-heavy object-oriented tradition that dominates JVM language design. Red remains largely outside mainstream enterprise development but represents an alternative philosophical lineage about what programming languages should look like and how they should handle data and code uniformly.
GraalVM is not a language itself but a high-performance JVM-based runtime developed by Oracle that changes the landscape for JVM language execution significantly. It includes a just-in-time compiler that outperforms the standard HotSpot compiler for many workloads, a ahead-of-time native image compiler that can convert JVM applications to standalone native executables with fast startup times, and a polyglot API that allows JavaScript, Python, Ruby, R, and other languages to run on the same runtime and share objects directly.
For JVM language designers, GraalVM’s Truffle framework provides a toolkit for building new language interpreters that automatically benefit from the GraalVM optimizer. Languages like TruffleRuby, GraalPython, and others use this infrastructure to achieve performance levels approaching or matching native implementations. GraalVM represents the most significant evolution of the JVM as a language platform in recent years, opening new possibilities for polyglot applications and raising the performance ceiling for dynamic language execution on Java infrastructure.
Java, the original JVM language, has undergone significant modernization through the OpenJDK project and its regular release cadence of two major versions per year since Java 9. Features that were previously available only in alternative JVM languages have been steadily introduced into Java itself, narrowing the gap between Java and its competitors. Records, sealed classes, pattern matching, text blocks, switch expressions, and local variable type inference have all been added in recent Java releases.
Project Loom brought virtual threads to Java in version 21, enabling lightweight concurrency at a scale that was previously only practical in languages with native coroutine or fiber support. Project Valhalla is working toward value types that allow developers to define classes whose instances are stored inline like primitives rather than on the heap, which will improve performance for numeric and small data-heavy workloads. These improvements mean that the choice between Java and alternative JVM languages is more nuanced than it was a decade ago, since Java itself now offers many of the features that once made alternatives compelling.
The JVM language ecosystem represents one of the richest and most diverse collections of programming language experiments and production tools ever assembled on a single runtime platform. From the functional purity of Clojure and Eta to the pragmatic modernism of Kotlin and the academic ambition of Scala, each language reflects a distinct set of priorities about what matters most in software development. The shared foundation of the JVM gives all of these languages access to decades of performance engineering, a vast library ecosystem, and deployment infrastructure that is trusted by organizations of every size.
What makes this ecosystem particularly valuable is that the languages are not isolated from each other. Kotlin and Java share the same bytecode and can call each other’s code freely. Groovy and Java coexist in many build systems. Scala’s Apache Spark accepts Python and SQL interfaces alongside its native Scala API. This interoperability means that choosing a JVM language does not mean abandoning the rest of the ecosystem, and teams can adopt new languages incrementally without rewriting existing infrastructure.
The future of JVM languages is shaped by several competing forces. GraalVM’s polyglot capabilities and native compilation are expanding what it means to be a JVM language, while Java’s own rapid modernization is reclaiming features that once distinguished alternatives. At the same time, newer languages like Kotlin continue to grow their communities and tooling, and functional languages like Clojure maintain devoted followings in specialized domains. For developers, this environment offers genuine choice rather than a false one, and the ability to select a language whose design philosophy aligns with the problem at hand, all while remaining part of the same connected and mature runtime world that the JVM has always promised.