skip to content

How does Spring Shell run in non-interactive (script) mode, and when would you choose it over interactive mode in production?

level: principalimportance: should knowfreq 20%

answer

  1. Args present => one-shot: run command, exit
  2. No args => interactive prompt
  3. spring.shell.interactive.enabled=false to disable prompt
  4. script command runs a file of commands
  5. Map failures to non-zero exit codes

basics

~20 s

Pass command-line arguments to the app and Spring Shell runs them as a single command, then exits instead of opening a prompt. This suits cron jobs, CI, and automation. You can also disable interactive mode via configuration.

solid answer

~40 s

Spring Shell supports two run modes. Interactive mode opens the REPL prompt when the app starts with no program arguments. Non-interactive (one-shot) mode kicks in when you pass command-line arguments: Spring Shell treats them as a single command, executes it, prints the result, and the process exits — ideal for scripting, cron, CI pipelines, and container entrypoints where you want a Spring-powered command without a human at a prompt. You can force it with configuration such as `spring.shell.interactive.enabled=false`. The `script` built-in runs a file of commands. In production, choose non-interactive for automation and reproducibility (exit codes, logs, idempotent invocations) and reserve interactive for operator consoles. Design considerations: meaningful exit codes on failure, no availability gates that assume prior interactive state, avoiding secrets on the command line, and structured/parseable output.

code

bash · 11 lines
bash
# Interactive: opens the REPL prompt
java -jar admin-tool.jar

# Non-interactive (one-shot): runs one command and exits
java -jar admin-tool.jar add-user alice --role ADMIN

# Force non-interactive so a container/CI never hangs on a prompt
java -jar admin-tool.jar --spring.shell.interactive.enabled=false batch-import --file users.csv

# Run a batch of commands from a file via the built-in script command
java -jar admin-tool.jar script ./ops-runbook.shell

go deeper

for a junior

Knows there is an interactive prompt.

for a middle

Knows passing arguments runs a single command and exits.

for a senior

Can configure interactive vs one-shot and use the script command; aware of exit-code needs.

for a principal

Designs command suites usable in both modes: proper exit codes, self-contained commands, machine-readable output, secret hygiene, and startup-cost tradeoffs.

**Two modes.** A Spring Shell app can run: 1. **Interactive (REPL).** Launched with no program arguments, it presents a prompt and loops reading commands. This is the default developer experience. 2. **Non-interactive / one-shot.** When you pass arguments to the program (`java -jar app.jar add-user alice --role ADMIN`), Spring Shell interprets them as a single command line, runs that one command, prints its output, and the JVM exits. No prompt is shown. This is how you use the same command definitions in automation. **Turning modes on/off.** Non-interactive behavior is triggered automatically by the presence of program arguments. You can also explicitly disable the interactive prompt via configuration (e.g. `spring.shell.interactive.enabled=false`) so the app never blocks on a prompt — useful in containers/CI where a hanging interactive shell would stall the pipeline. Conversely you keep it enabled for operator consoles. **Scripts.** The built-in `script` command executes a file whose lines are commands, running them in sequence. This lets you batch a series of operations. Combined with one-shot mode you can also feed commands from files/stdin depending on configuration. **Why choose non-interactive in production.** - **Automation & scheduling.** Cron jobs, CI/CD steps, Kubernetes Jobs, and container entrypoints need a command that runs and terminates. - **Reproducibility & auditability.** A recorded command line plus logs is repeatable and reviewable. - **Exit codes.** Automation branches on process exit status; ensure failures produce a non-zero code (via an `ExitCodeExceptionMapper`/throwing, or Spring Boot's exit-code support) rather than exiting 0 on error. - **Composability.** Output can be piped into other tools if it is parseable. **Design considerations / gotchas for the principal.** - **Exit codes matter.** Interactive shells swallow errors into a message; in one-shot mode you must map failures to non-zero exit codes so pipelines detect them. This is a frequent mistake. - **Stateful availability breaks scripting.** A command gated on prior interactive state (e.g. requires a preceding `connect`) will be unavailable in a fresh one-shot invocation. Design commands to be self-contained or accept connection parameters. - **Secrets on the command line.** Arguments are visible in process listings and shell history; pass secrets via environment/config/files, not options. - **Output format.** Human-friendly tables are hard to parse; offer a machine-readable option (JSON) for automation. - **Startup cost.** Each one-shot run pays full Spring context startup; for high-frequency invocation consider keeping a long-lived process or a different tool. - **Idempotency.** Automated re-runs (retries) should be safe. **When to use which.** Interactive: exploratory ops, incident response, developer consoles. Non-interactive: everything automated. The value of Spring Shell here is reusing one command implementation (with DI, config, validation) across both a human console and scripted automation.

  • What triggers non-interactive mode?
    Passing program arguments to the application: Spring Shell runs them as a single command and exits instead of opening the prompt. You can also disable the prompt explicitly via spring.shell.interactive.enabled=false.
  • What is the most common production pitfall with one-shot mode?
    Not propagating failures as non-zero exit codes, so CI/cron thinks a failed command succeeded. Map exceptions to exit codes (Spring Boot exit-code support / ExitCodeExceptionMapper).
  • Why can a command that works interactively fail in a script?
    If its availability depends on prior interactive state (e.g. a previous connect), a fresh one-shot invocation lacks that state and the command is unavailable. Make commands self-contained.

saying these in an interview costs you the question

  • Believing Spring Shell can only run interactively
  • Assuming a failed one-shot command automatically returns a non-zero exit code
  • Passing secrets as plain command-line options in automation
  • Relying on interactive-established state inside scripted invocations

context