The Groovy Shell (groovysh) REPL is covered here with 10 tested examples. Learn commands, tab completion, multi-line input, imports, and scripting tips on Groovy 5.x.
“The best way to learn a language is to have a conversation with it. A REPL is that conversation.”
Brian Kernighan, The Unix Programming Environment
Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner | Reading Time: 14 minutes
If you’ve installed Groovy and want a quick way to experiment with code without creating files, the Groovy Shell (groovysh) is your best friend. As described in the official Groovy integration documentation, it’s an interactive REPL (Read-Eval-Print Loop) that ships with every Groovy installation. You type an expression, press Enter, and see the result immediately. No compilation step, no boilerplate, no project setup.
This post covers how to launch groovysh, use its built-in commands, handle multi-line input, import libraries, define classes and methods on the fly, load external scripts, pull in dependencies with @Grab, inspect objects, and understand when to use groovysh versus the other Groovy execution tools.
If you’re brand new to Groovy, start with our Groovy Hello World tutorial. If you’ve already used the groovy -e command for one-liners, this is the natural next step – see our Groovy Command Line -e Option guide for comparison.
Table of Contents
What Is groovysh?
groovysh is the interactive command-line shell that ships with the Groovy SDK. It provides a REPL environment where you can type Groovy expressions and statements, see results immediately, and build up code incrementally. Think of it as a scratchpad for Groovy – perfect for learning, prototyping, testing API calls, and debugging.
Key features of groovysh:
- Instant feedback – every expression is evaluated and the result is printed immediately
- Tab completion – press Tab to auto-complete class names, method names, and variables
- Multi-line input – define classes, closures, and complex statements across multiple lines
- Built-in commands –
:help,:clear,:load,:save,:quit, and more - History – arrow keys navigate through previous commands, and history persists across sessions
- Import support – import any class on the classpath, including
@Grabdependencies
Getting Started with groovysh
To launch the Groovy Shell, open a terminal and type:
Launching groovysh
groovysh
You’ll see a prompt like this:
Groovy Shell (5.0.0, JVM: 17.0.x) Type ':help' or ':h' for help. ------------------------------------- groovy:000>
The groovy:000> prompt tells you the shell is ready. The number after the colon is the line counter within the current buffer. When you type a complete statement and press Enter, the shell evaluates it and prints the result prefixed with ===>.
You can also launch groovysh with options:
groovysh -q– quiet mode, suppresses the startup bannergroovysh -cp /path/to/lib/*– add JARs to the classpathgroovysh -D property=value– set system propertiesgroovysh -e "println 'hello'"– evaluate an expression and exit
10 Practical Examples
Let’s work through 10 tested examples that cover the key techniques for being productive in groovysh. Every example below was tested on Groovy 5.x with Java 17+.
Example 1: Launching groovysh and Basic Expressions
What we’re doing: Evaluating basic arithmetic, string operations, and Groovy expressions directly in the shell. This is the simplest use case – treating groovysh as a calculator and quick-test environment.
Example 1: Basic Expressions in groovysh
// Arithmetic
groovy:000> 2 + 3
===> 5
// String interpolation
groovy:000> name = "Groovy"
===> Groovy
groovy:000> "Hello, ${name}!"
===> Hello, Groovy!
// List operations
groovy:000> [1, 2, 3, 4, 5].collect { it * 2 }
===> [2, 4, 6, 8, 10]
// Map literal
groovy:000> [language: 'Groovy', version: '5.0']
===> [language:Groovy, version:5.0]
// Type checking
groovy:000> 42.class
===> class java.lang.Integer
groovy:000> "hello".class
===> class java.lang.String
// Boolean expressions
groovy:000> 10 > 5 && "groovy".startsWith("g")
===> true
Notice that you don’t need println to see results. The REPL automatically prints the return value of each expression after the ===> marker. If an expression returns null, the shell prints ===> null. When you use println, the output appears on its own line before the ===> marker.
Understanding the result indicator: The ===> output is the return value of the expression, not standard output. This distinction matters. If you type println "hello", you’ll see hello on one line (that’s stdout) followed by ===> null (that’s the return value, since println returns void/null). If you type "hello" by itself, you’ll only see ===> hello because the string expression’s return value is the string itself.
This is a great place to experiment with Groovy’s operators and GDK methods. Try things like "hello" * 3, [1,2,3] + [4,5], or (1..10).step(2) and see what comes back. The instant feedback loop is what makes a REPL so effective for learning.
Example 2: Variables and Multi-line Input
What we’re doing: Declaring variables and writing multi-line statements. The shell detects incomplete code (like an unclosed brace or parenthesis) and waits for more input.
Example 2: Variables and Multi-line Input
// Variables persist across lines in the same session
groovy:000> firstName = "John"
===> John
groovy:000> lastName = "Doe"
===> Doe
groovy:000> "${firstName} ${lastName}"
===> John Doe
// Using def keyword
groovy:000> def age = 30
===> 30
groovy:000> age
===> 30
// Multi-line input - the shell detects the opening brace
groovy:000> def greet(name) {
groovy:001> return "Welcome, ${name}!"
groovy:002> }
===> true
groovy:000> greet("Alice")
===> Welcome, Alice!
// Multi-line closures
groovy:000> def numbers = [3, 1, 4, 1, 5, 9, 2, 6]
===> [3, 1, 4, 1, 5, 9, 2, 6]
groovy:000> numbers.findAll {
groovy:001> it > 3
groovy:002> }.sort()
===> [4, 5, 6, 9]
// Multi-line if/else
groovy:000> x = 42
===> 42
groovy:000> if (x > 40) {
groovy:001> "big number"
groovy:002> } else {
groovy:003> "small number"
groovy:004> }
===> big number
When you open a brace, parenthesis, or bracket, the shell prompt changes from groovy:000> to groovy:001>, groovy:002>, and so on. This tells you the shell is waiting for more input to complete the statement. Once all brackets are balanced and the statement is complete, the shell evaluates it.
Important note on def: Variables declared with def in groovysh are scoped to the current evaluation. If you want a variable to persist across multiple inputs, omit the def keyword – this binds the variable to the shell’s binding context. For more on def, see our Groovy def Keyword guide.
A quick test to see the difference:
def Scoping in groovysh
// Without def - variable persists groovy:000> color = "blue" ===> blue groovy:000> color ===> blue // With def - variable is local to that evaluation groovy:000> def shape = "circle" ===> circle groovy:000> shape ERROR groovy.lang.MissingPropertyException: No such property: shape for class: groovysh_evaluate
This behavior catches many beginners off guard. The rule is simple: if you want to keep it, don’t use def. This is the opposite of how def works in a regular Groovy script, where def declares a local variable within the script’s scope.
Example 3: Built-in Commands (:help, :clear, :quit, :load, :save)
What we’re doing: Exploring the built-in colon commands that control the shell itself. These are not Groovy code – they’re shell meta-commands that start with a colon.
Example 3: Built-in Commands
// Display all available commands groovy:000> :help Available commands: :help (:h ) Display this help message :? (:? ) Alias to: :help :exit (:x ) Exit the shell :quit (:q ) Alias to: :exit :import (:i ) Import a class into the namespace :display (:d ) Display the current buffer :clear (:c ) Clear the buffer and reset the prompt counter :show (:S ) Show variables, classes, or imports :inspect (:n ) Inspect a variable or last result with the GUI object browser :purge (:p ) Purge variables, classes, imports, or preferences :edit (:e ) Edit the current buffer :load (:l ) Load a file or URL into the buffer :save (:s ) Save the current buffer to a file :record (:r ) Record the current session to a file :history (:H ) Display, manage, and recall edit-line history :alias (:a ) Create an alias :set (:= ) Set (or list) preferences :grab (:g ) Add a dependency to the shell environment :register (:rc) Register a new command with the shell :doc (:D ) Open a browser window displaying the doc for the argument // Clear the current buffer (useful if you started typing something wrong) groovy:000> x = 10 ===> 10 groovy:000> :clear groovy:000> // Show all variables in the current session groovy:000> name = "Groovy" ===> Groovy groovy:000> version = 5 ===> 5 groovy:000> :show variables Variables: name = Groovy version = 5 // Show all imports groovy:000> :show imports imports: ...default imports... // Show command history groovy:000> :history 1 name = "Groovy" 2 version = 5 3 :show variables // Exit the shell groovy:000> :quit
Each command has a long form (like :help) and a short alias (like :h). You’ll use :clear frequently when you make a typo in a multi-line statement and want to start over. The :show variables command is handy for checking what’s currently defined in your session.
The :purge command is worth knowing about separately. It lets you selectively clean up your session:
:purge variables– removes all variables from the binding:purge classes– removes all class definitions:purge imports– removes all user-added imports (default imports remain):purge all– clears everything and resets the session to a clean state
The :set command controls shell preferences. For example, :set show-last-result false stops the shell from printing the ===> result line after each expression. Run :set with no arguments to see all available preferences and their current values.
Example 4: Tab Completion and Code Assistance
What we’re doing: Using tab completion to discover methods, properties, and class names without leaving the shell. This is one of the most productive features of groovysh.
Example 4: Tab Completion
// Type a string and press Tab after the dot to see available methods groovy:000> "hello".to [TAB] toBoolean() toCharacter() toDouble() toFloat() toInteger() toList() toLong() toLowerCase() toSet() toShort() toString() toUpperCase() toURI() toURL() // Complete class names groovy:000> java.util.Array [TAB] ArrayList ArrayDeque Arrays // Complete after partial method name groovy:000> [1,2,3].col [TAB] collect( collectEntries( collectMany( collectNested( // Works with your own variables too groovy:000> myMap = [a: 1, b: 2, c: 3] ===> [a:1, b:2, c:3] groovy:000> myMap.find [TAB] find( findAll( findResult( findResults( // Tab on an empty line after an import shows all available classes groovy:000> import java.time.Local [TAB] LocalDate LocalDateTime LocalTime
Tab completion works on class names, method names, variable names, and even package names. It introspects the actual objects at runtime, so it shows methods that are really available – including GDK (Groovy Development Kit) methods that Groovy adds to Java classes. This makes groovysh a great tool for API exploration.
Pro tip: If tab completion seems slow on the first use, that’s because the shell is loading class metadata. Subsequent completions in the same session are much faster. You can also use the :doc command to open Javadoc/Groovydoc in a browser for any class: :doc java.util.HashMap opens the HashMap documentation directly.
Tab completion is context-aware. If you type new java.util. and press Tab, it shows classes you can instantiate. If you type a variable name followed by a dot and press Tab, it shows the methods and properties available on that specific object’s type. This runtime introspection is more accurate than static analysis because it reflects the actual state of the object.
Example 5: Importing Classes and Packages
What we’re doing: Importing classes into the shell session so you can use them without fully qualified names. Groovy’s default imports are already available, but you’ll often need additional ones.
Example 5: Importing Classes
// Groovy's default imports are already available
groovy:000> new Date()
===> Tue Mar 10 14:30:00 IST 2026
groovy:000> new ArrayList()
===> []
// Import additional classes with the import statement
groovy:000> import java.time.LocalDate
===> java.time.LocalDate
groovy:000> LocalDate.now()
===> 2026-03-10
// Import with alias
groovy:000> import java.time.format.DateTimeFormatter as DTF
===> java.time.format.DateTimeFormatter
groovy:000> LocalDate.now().format(DTF.ofPattern("dd-MMM-yyyy"))
===> 10-Mar-2026
// Use the :import command (equivalent)
groovy:000> :import java.util.concurrent.atomic.AtomicInteger
groovy:000> counter = new AtomicInteger(0)
===> 0
groovy:000> counter.incrementAndGet()
===> 1
// Import static members
groovy:000> import static java.lang.Math.PI
===> java.lang.Math.PI
groovy:000> PI
===> 3.141592653589793
// Wildcard import
groovy:000> import java.nio.file.*
===> java.nio.file.*
groovy:000> Files.exists(Path.of("/tmp"))
===> true
// Check all current imports
groovy:000> :show imports
Groovy automatically imports java.lang.*, java.util.*, java.io.*, java.net.*, groovy.lang.*, groovy.util.*, java.math.BigDecimal, and java.math.BigInteger. Everything else needs an explicit import. Once imported in a session, the import persists until you close the shell or use :purge imports.
Example 6: Defining Classes and Methods in REPL
What we’re doing: Creating classes, methods, and closures directly in the shell. This is useful for prototyping data structures and algorithms before committing them to a file.
Example 6: Defining Classes and Methods
// Define a simple class
groovy:000> class Person {
groovy:001> String name
groovy:002> int age
groovy:003> String toString() { "${name} (age: ${age})" }
groovy:004> }
===> true
// Create instances
groovy:000> alice = new Person(name: "Alice", age: 30)
===> Alice (age: 30)
groovy:000> bob = new Person(name: "Bob", age: 25)
===> Bob (age: 25)
// Use the class
groovy:000> people = [alice, bob]
===> [Alice (age: 30), Bob (age: 25)]
groovy:000> people.sort { it.age }
===> [Bob (age: 25), Alice (age: 30)]
// Define a standalone method
groovy:000> def factorial(n) {
groovy:001> n <= 1 ? 1 : n * factorial(n - 1)
groovy:002> }
===> true
groovy:000> factorial(10)
===> 3628800
// Define and use closures
groovy:000> doubler = { it * 2 }
===> groovysh_evaluate$_run_closure1@3a71c100
groovy:000> (1..5).collect(doubler)
===> [2, 4, 6, 8, 10]
// Enum definitions work too
groovy:000> enum Color { RED, GREEN, BLUE }
===> true
groovy:000> Color.values()
===> [RED, GREEN, BLUE]
groovy:000> Color.GREEN.name()
===> GREEN
// Show all defined classes
groovy:000> :show classes
Classes defined in the shell live for the duration of the session. You can redefine a class by entering the same class definition again – the new definition replaces the old one. However, existing instances of the old class won’t be updated. If you get into a messy state, use :purge classes to clear all class definitions and start fresh.
Interfaces and traits work too. You can define interfaces, abstract classes, and even Groovy traits directly in the REPL:
Interfaces and Traits in groovysh
// Define a trait
groovy:000> trait Greetable {
groovy:001> String greet() { "Hello, I'm ${name}" }
groovy:002> }
===> true
// Use it in a class
groovy:000> class Employee implements Greetable {
groovy:001> String name
groovy:002> String department
groovy:003> }
===> true
groovy:000> emp = new Employee(name: "Carol", department: "Engineering")
===> Employee@4a5905d9
groovy:000> emp.greet()
===> Hello, I'm Carol
This makes groovysh a complete prototyping environment. You can define full class hierarchies, test their interactions, and iterate on the design before moving the code to a proper project file.
Example 7: Loading External Scripts with :load
What we’re doing: Loading Groovy scripts from disk into the shell session. This lets you prepare utility functions in a file and bring them into your interactive session.
Example 7: Loading External Scripts
// First, assume we have a file called utils.groovy with this content:
// --- utils.groovy ---
// def add(a, b) { a + b }
// def multiply(a, b) { a * b }
// greeting = "Hello from utils.groovy!"
// println "Utils loaded successfully."
// --- end of file ---
// Load the script into the shell
groovy:000> :load utils.groovy
Utils loaded successfully.
===> Hello from utils.groovy!
// Now the functions and variables are available
groovy:000> add(3, 7)
===> 10
groovy:000> multiply(4, 5)
===> 20
groovy:000> greeting
===> Hello from utils.groovy!
// Load from an absolute path
groovy:000> :load /home/user/scripts/helpers.groovy
// Load from a URL
groovy:000> :load https://example.com/scripts/sample.groovy
// Save the current session to a file
groovy:000> x = 10
===> 10
groovy:000> y = 20
===> 20
groovy:000> x + y
===> 30
groovy:000> :save session.groovy
// Record the session (captures everything you type)
groovy:000> :record start mySession.txt
Recording current session to: mySession.txt
groovy:000> println "This will be recorded"
This will be recorded
===> null
groovy:000> :record stop
Recording stopped; session saved to: mySession.txt
The :load command executes the script as if you had typed each line into the shell. Variables and methods defined in the script become available in the current session. The :save command writes the contents of the current buffer to a file. The :record command captures your entire interactive session, which is useful for creating tutorials or documenting exploration sessions.
Creating a reusable startup script: A common pattern is to create a file called groovysh-init.groovy with your frequently used imports, utility methods, and configuration. Then start each session with :load groovysh-init.groovy. Here’s an example of what that file might contain:
Sample groovysh-init.groovy
// groovysh-init.groovy - load this at the start of each session
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
// Utility methods
def now() { LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) }
def parseJson(text) { new JsonSlurper().parseText(text) }
def prettyJson(obj) { JsonOutput.prettyPrint(JsonOutput.toJson(obj)) }
println "Session initialized at ${now()}"
println "Available: now(), parseJson(text), prettyJson(obj)"
With this file loaded, you have instant access to date formatting and JSON utilities without typing the imports every time. This is especially valuable if you use groovysh daily for data exploration or API testing.
Example 8: Using @Grab in groovysh
What we’re doing: Pulling in external dependencies directly from Maven repositories using @Grab. This makes groovysh a useful tool for testing third-party libraries without a build file. For more details into dependency management, see our Groovy Grape guide.
Example 8: Using @Grab in groovysh
// Grab Apache Commons Lang for string utilities
groovy:000> :grab 'org.apache.commons:commons-lang3:3.14.0'
groovy:000> import org.apache.commons.lang3.StringUtils
===> org.apache.commons.lang3.StringUtils
groovy:000> StringUtils.capitalize("groovy shell")
===> Groovy shell
groovy:000> StringUtils.reverse("hello")
===> olleh
// Alternative: use @Grab annotation syntax
groovy:000> @Grab('com.google.code.gson:gson:2.11.0')
groovy:001> import com.google.gson.Gson
===> com.google.gson.Gson
groovy:000> gson = new Gson()
===> {}
groovy:000> gson.toJson([name: "Alice", age: 30])
===> {"name":"Alice","age":30}
// Parse JSON back
groovy:000> json = '{"city":"London","pop":9000000}'
===> {"city":"London","pop":9000000}
groovy:000> gson.fromJson(json, Map)
===> {city=London, pop=9000000.0}
// Use Groovy's built-in JSON support (no @Grab needed)
groovy:000> import groovy.json.JsonSlurper
===> groovy.json.JsonSlurper
groovy:000> new JsonSlurper().parseText('{"framework":"Grails","version":7}')
===> [framework:Grails, version:7]
// Grab with specific repository
groovy:000> @GrabResolver(name='jcenter', root='https://jcenter.bintray.com/')
groovy:001> @Grab('org.codehaus.gpars:gpars:1.2.1')
groovy:002> import groovyx.gpars.GParsPool
The :grab command and @Grab annotation both use Grape, Groovy’s built-in dependency manager. The first time you grab a dependency, it downloads from Maven Central (or whichever repository you specify) and caches it in ~/.groovy/grapes/. Subsequent uses load from cache. This makes groovysh incredibly useful for quickly testing a library’s API before adding it to your project’s build file.
Troubleshooting @Grab in groovysh: If @Grab throws a resolution error, check your network connection and proxy settings. You can configure proxy settings in ~/.groovy/grapeConfig.xml. If a dependency has transitive conflicts, use @GrabExclude to exclude specific transitive dependencies. Also, remember that @Grab resolves dependencies at the point it’s evaluated – so it must appear before the import statement for the classes you want to use from that dependency.
For a complete guide on Grape’s configuration options, repository management, and advanced dependency resolution, see our dedicated Groovy Grape post.
Example 9: Inspecting Objects and Types
What we’re doing: Examining object types, available methods, properties, and class hierarchies. The REPL is an excellent tool for runtime introspection.
Example 9: Inspecting Objects and Types
// Check the type of any expression
groovy:000> 42.class
===> class java.lang.Integer
groovy:000> 42.class.name
===> java.lang.Integer
groovy:000> 3.14.class
===> class java.math.BigDecimal
groovy:000> [1, 2, 3].class
===> class java.util.ArrayList
// List all methods on an object
groovy:000> "hello".metaClass.methods*.name.unique().sort()
===> [asBoolean, asType, capitalize, center, charAt, chars, ...]
// Check if an object responds to a method
groovy:000> "hello".respondsTo("toUpperCase")
===> [public java.lang.String java.lang.String.toUpperCase(), ...]
groovy:000> "hello".respondsTo("nonExistent")
===> []
// Explore properties
groovy:000> myList = [10, 20, 30]
===> [10, 20, 30]
groovy:000> myList.metaClass.properties*.name
===> [class, empty]
groovy:000> myList.empty
===> false
// Inspect class hierarchy
groovy:000> Integer.superclass
===> class java.lang.Number
groovy:000> Integer.interfaces*.name
===> [java.lang.Comparable]
// The :inspect command opens a visual object browser (if GUI is available)
groovy:000> data = [name: "Groovy", version: 5, features: ["REPL", "DSL", "AST"]]
===> [name:Groovy, version:5, features:[REPL, DSL, AST]]
groovy:000> :inspect data
// Use dump() for a quick text dump
groovy:000> new Date().dump()
===> <java.util.Date@... fastTime=1741598400000 ...>
// Use .properties for JavaBean-style inspection
groovy:000> import java.time.LocalDate
===> java.time.LocalDate
groovy:000> today = LocalDate.now()
===> 2026-03-10
groovy:000> today.properties
===> [dayOfWeek:TUESDAY, dayOfMonth:10, month:MARCH, year:2026, ...]
// Get GDK methods added by Groovy
groovy:000> (String.metaClass.methods - java.lang.String.methods)*.name.unique().sort().take(10)
===> [asBoolean, asType, capitalize, center, collectReplacements, ...]
This kind of introspection is what makes a REPL so valuable. Instead of reading documentation, you can poke at live objects, discover their methods, and test them immediately. The combination of tab completion (Example 4) and runtime inspection gives you a very fast feedback loop for learning new APIs.
Practical use case – exploring an unfamiliar API: Imagine you need to work with Java’s java.time API but aren’t sure what methods are available on LocalDate. Instead of searching the Javadoc, you can do this:
Exploring APIs Interactively
groovy:000> import java.time.LocalDate
===> java.time.LocalDate
groovy:000> today = LocalDate.now()
===> 2026-03-10
// What methods start with "plus"?
groovy:000> today.metaClass.methods*.name.findAll { it.startsWith("plus") }.unique()
===> [plusDays, plusWeeks, plusMonths, plusYears]
// Try one
groovy:000> today.plusWeeks(2)
===> 2026-03-24
// What about "get" methods?
groovy:000> today.metaClass.methods*.name.findAll { it.startsWith("get") }.unique().sort()
===> [getChronology, getClass, getDayOfMonth, getDayOfWeek, getDayOfYear, getEra, getLong, getMonth, getMonthValue, getYear]
groovy:000> today.getDayOfWeek()
===> TUESDAY
groovy:000> today.getDayOfYear()
===> 69
This interactive discovery workflow is significantly faster than switching between your editor and documentation. You can test edge cases, verify behavior, and build confidence in an API before writing production code.
Example 10: groovysh vs groovyConsole vs groovy -e
What we’re doing: Comparing the three main ways to run Groovy code interactively. Each has its sweet spot, and knowing when to use which saves time.
Example 10: Comparison of Groovy Execution Tools
// === groovysh (Interactive REPL) ===
// Launch: groovysh
// Best for: exploration, learning, API testing, quick calculations
// Features: tab completion, history, :commands, session persistence
//
// groovy:000> [1,2,3].sum()
// ===> 6
// === groovyConsole (GUI Editor + REPL) ===
// Launch: groovyConsole
// Best for: writing longer scripts with visual feedback, AST inspection
// Features: syntax highlighting, AST browser, output pane, script editor
//
// Write code in the editor area, press Ctrl+R to run
// def result = (1..100).findAll { it % 7 == 0 }
// println result
// === groovy -e (One-liner Execution) ===
// Launch: groovy -e 'println "Hello"'
// Best for: shell scripts, CI/CD pipelines, quick one-off commands
// Features: non-interactive, can be piped, works in shell scripts
//
// $ groovy -e 'println new Date().format("yyyy-MM-dd")'
// 2026-03-10
Here’s a side-by-side comparison table to help you choose:
| Feature | groovysh | groovyConsole | groovy -e |
|---|---|---|---|
| Interface | Command-line REPL | GUI (Swing-based) | Single command |
| Interactive | Yes | Yes | No |
| Tab completion | Yes | No | No |
| Multi-line editing | Line by line | Full editor | Single expression |
| Syntax highlighting | No | Yes | No |
| AST browser | No | Yes | No |
| Session history | Yes (persistent) | Per window | No |
| Best for | Exploration, learning | Prototyping scripts | Automation, CI/CD |
| SSH friendly | Yes | No (needs display) | Yes |
| @Grab support | Yes | Yes | Yes |
Rule of thumb: Use groovysh when you want to explore and experiment interactively on a terminal. Use groovyConsole when you want a visual editor with syntax highlighting and the AST browser. Use groovy -e when you need a one-liner in a shell script or CI pipeline. For more on the -e option, check out our Groovy Command Line -e Option guide.
When to use groovysh specifically:
- Learning Groovy syntax – test each concept as you read about it
- Exploring a new library’s API –
@Grabit, import it, and call methods to see what they do - Quick data transformations – parse a JSON file, filter some data, format the output
- Debugging – reproduce an issue in isolation by copying the relevant code into the REPL
- Working on remote servers via SSH – no GUI needed, just a terminal
- Quick calculations – it’s a powerful calculator that understands dates, strings, collections, and math
When NOT to use groovysh:
- Writing scripts longer than 20-30 lines – use a proper editor and run with
groovy scriptname.groovy - Code that needs syntax highlighting – use
groovyConsoleor your IDE - Automated pipelines – use
groovy -eor run a script file directly - AST debugging –
groovyConsolehas a built-in AST browser thatgroovyshlacks
Best Practices
Session Management
- Avoid
deffor variables you want to reuse – Variables declared withdefingroovyshare scoped to the current evaluation buffer. Omitdefto bind variables to the shell session so they persist across inputs. - Use
:recordfor important sessions – When you’re exploring an API or debugging a problem, start recording with:record start filename.txt. You’ll thank yourself later when you need to reproduce what you did. - Use
:clearliberally – If you’re mid-way through a multi-line statement and realize you made a mistake,:clearresets the buffer instantly rather than trying to fix the syntax error. - Create startup scripts – Place commonly used imports and utility functions in a file and
:loadit at the start of each session to save repetitive typing.
Performance and Memory
- Watch memory in long sessions – Every variable and class definition stays in memory. For long exploration sessions, use
:purge variablesor:purge allperiodically to free resources. - Use
-cpinstead of@Grabfor large libraries – If you’re repeatedly using the same libraries, launchinggroovysh -cp /path/to/libs/*is faster than@Grabbecause it skips the dependency resolution step. - Increase heap for heavy work – Set
JAVA_OPTS="-Xmx512m"before launchinggroovyshif you’re working with large datasets or many dependencies.
Productivity Tips
- Use arrow keys for history – Up/Down arrows navigate through previous commands. The history persists across sessions in
~/.groovy/groovysh.history. - Ctrl+R for reverse search – Just like in Bash, Ctrl+R searches your command history backward. Type a fragment and it finds the last matching command.
- Use
_for the last result – The underscore variable_holds the result of the last evaluated expression, so you can chain operations without assigning intermediate results to variables. - Pipe output for scripting – Combine
groovyshwith shell pipelines:echo 'println System.properties["os.name"]' | groovysh -q.
Common Pitfalls to Avoid
- Don’t confuse
groovyshwith the system shell – Shell commands likels,cd, ordirdon’t work ingroovysh. If you need to run system commands, use"ls -la".execute().text(Groovy’s process execution). See our Groovy Hello World guide for the basics. - Don’t redefine a class and expect old instances to update – If you create
alice = new Person(name: "Alice"), then redefineclass Personwith new fields,alicestill references the old class definition. Create new instances after redefining. - Watch out for semicolons – Unlike some REPLs,
groovyshtreats each line as a potential complete statement. If you want multiple statements on one line, separate them with semicolons:x = 10; y = 20; x + y. - Don’t ignore error messages – When you get a
MissingPropertyExceptionorMissingMethodException, read the message carefully. It often tells you the exact class where the lookup failed, which helps diagnose whether you have a scoping issue, a typo, or a missing import. - Beware of infinite loops – If you accidentally create an infinite loop in
groovysh, pressCtrl+Cto interrupt it. The shell will catch the interrupt and return you to the prompt. IfCtrl+Cdoesn’t work, you may need to close the terminal.
Environment Configuration
You can customize groovysh behavior through environment variables and configuration files:
GROOVY_HOME– Must point to your Groovy installation directoryJAVA_OPTS– Set JVM options like-Xmx512mfor increased heap or-Dhttp.proxyHost=...for proxy configuration~/.groovy/groovysh.profile– If this file exists,groovyshloads it automatically at startup. Place your default imports and utility methods here for zero-effort session initialization~/.groovy/groovysh.history– Command history is persisted here across sessions. You can edit or clear this file manually if needed
The groovysh.profile file is particularly powerful. Unlike :load, which you run manually each session, the profile runs automatically every time you start groovysh. Put your most common imports, date/JSON utilities, and database connection helpers there, and they’ll always be available.
Conclusion
The Groovy Shell (groovysh) is one of the most underused tools in the Groovy ecosystem. It gives you instant feedback, tab completion, session persistence, and the ability to pull in any Maven dependency on the fly with @Grab. It works well for learning Groovy, prototyping algorithms, testing library APIs, and debugging data transformations – all faster than creating a project and writing a full script.
We covered 10 practical examples: from basic expressions and multi-line input to built-in commands, tab completion, imports, class definitions, loading scripts, dependency management, object inspection, and the comparison between Groovy’s three execution tools. With these techniques, you can make groovysh a central part of your Groovy workflow.
Summary
- groovysh is a REPL that ships with every Groovy installation – no extra setup required
- Tab completion and command history make exploration fast and efficient
- Built-in commands like
:help,:clear,:load,:save, and:recordmanage your session - @Grab pulls in any Maven dependency on the fly – no build file needed
- Omit
deffor session-persistent variables; usedeffor temporary ones - :load brings external scripts into your session for reusable utility functions
- Runtime introspection with
.class,.metaClass, and.propertiesis invaluable for learning APIs
If you also work with build tools, CI/CD pipelines, or cloud CLIs, check out Command Playground to practice 105+ CLI tools directly in your browser — no install needed.
Up next: Groovy Custom Annotations
Frequently Asked Questions
What is groovysh and how do I start it?
groovysh is the interactive REPL (Read-Eval-Print Loop) shell that ships with every Groovy installation. To start it, open a terminal and type groovysh. You’ll see a prompt like groovy:000> where you can type Groovy expressions and see results immediately. It requires no project setup, no build files, and no IDE – just a working Groovy installation.
How do I handle multi-line code in groovysh?
groovysh automatically detects incomplete statements. When you type an opening brace {, parenthesis (, or bracket [, the prompt counter increments (e.g., groovy:001>) and waits for more input. Once all brackets are balanced and the statement is complete, the shell evaluates it. If you make a mistake in a multi-line block, type :clear to reset the buffer and start over.
Why does my variable disappear after I define it with def in groovysh?
Variables declared with def in groovysh are scoped to the current evaluation context. To create a variable that persists across multiple inputs in the same session, omit the def keyword – for example, write name = "Alice" instead of def name = "Alice". This binds the variable to the shell’s global binding, making it accessible throughout the session.
Can I use external libraries in groovysh?
Yes. You can pull in any Maven dependency using the :grab command (e.g., :grab 'org.apache.commons:commons-lang3:3.14.0') or the @Grab annotation. Groovy’s Grape dependency manager downloads the JAR from Maven Central and caches it locally. You can also launch groovysh with a classpath: groovysh -cp /path/to/jars/* for faster startup when using the same libraries repeatedly.
What is the difference between groovysh, groovyConsole, and groovy -e?
groovysh is a command-line REPL with tab completion and session history – ideal for interactive exploration on a terminal. groovyConsole is a GUI application with a script editor, syntax highlighting, and an AST browser – best for writing and testing longer scripts visually. groovy -e executes a single Groovy expression non-interactively – perfect for shell scripts and CI/CD pipelines. All three support @Grab for dependency management.
Related Posts
Previous in Series: Groovy Logging
Next in Series: Groovy Custom Annotations
Related Topics You Might Like:
This post is part of the Groovy Cookbook series on TechnoScripts.com

No comment