A fast, interactive CLI for generating Spring Boot projects directly from your terminal, powered by Spring Initializr.
$ sprout new my-api --deps web,data-jpa,postgresql --java 21
Generating my-api from start.spring.io…
✓ Created my-api in ./my-api (10 files)
Gradle - Groovy · Java 21 · Spring Boot 4.1.2 · Jar
Dependencies: web, data-jpa, postgresql
Next steps:
cd ./my-api
./gradlew bootRunNote: Sprout is an independent, community CLI client for the public Spring Initializr API. It is not an official Spring project and is not affiliated with or endorsed by the Spring team or Broadcom. "Spring" and "Spring Boot" are trademarks of their respective owners.
- Why Sprout?
- Installation
- Quick start
- Command guide
- Interactive mode
- Flag-based mode
- Adding and removing dependencies
- Creating classes, records and packages
- Zed integration
- Dependency search
- Spring Boot versions and server options
- Presets
- Configuration
- Cache and offline use
- Shell completion
- Safety guarantees
- How Sprout uses Spring Initializr
- Troubleshooting
- Development
- Contributing
- License
start.spring.io is great, but sometimes you just want a project without leaving the terminal. Sprout gives you:
- The full Initializr feature set. Sprout reads the server's metadata at runtime, so it offers every project type, language, Spring Boot version, Java version, packaging, configuration format and dependency the server offers. Nothing is hardcoded, so new Spring Boot releases and dependencies show up automatically.
- A keyboard-first wizard with searchable, multi-select dependencies, and a flag mode for scripts and CI, with the same options in both.
- Validation before download. Unknown dependency IDs, incompatible
dependency/Boot combinations and unsupported values are caught locally, with
suggestions (
did you mean data-jpa?). - Safe, atomic project creation. The archive is downloaded and extracted in a temporary directory, checked for path-traversal attacks, and moved into place only when complete. Existing files are never silently overwritten.
- Add or remove dependencies in existing projects (
sprout add lombok) with exactly the build changes start.spring.io would make. - Typo-tolerant names:
datajpabecomesdata-jpa, and close matches are offered for the rest. - Presets, defaults, history, Git and editor integration.
- A single static binary for Linux, macOS and Windows. No Java needed to generate a project.
Download the archive for your platform from the
releases page, extract it and put
sprout (or sprout.exe) on your PATH. Builds are available for:
| OS | amd64 | arm64 |
|---|---|---|
| Linux | ✓ | ✓ |
| macOS | ✓ | ✓ |
| Windows | ✓ | ✓ |
# Example: Linux x86-64
VERSION=0.2.1
curl -LO https://github.com/maskedsyntax/sprout/releases/download/v${VERSION}/sprout_${VERSION}_linux_amd64.tar.gz
tar -xzf sprout_${VERSION}_linux_amd64.tar.gz sprout
sudo install sprout /usr/local/bin/Each release includes a checksums.txt for verification (sha256sum -c checksums.txt --ignore-missing).
Requires Go 1.26 or newer:
go install github.com/maskedsyntax/sprout/cmd/sprout@latestgit clone https://github.com/maskedsyntax/sprout
cd sprout
make build # produces ./bin/sprout with version informationDownload a newer release, or re-run go install …@latest. Check your version with
sprout --version.
sprout new # interactive wizard
sprout new my-api # wizard, name pre-filled
sprout new my-api --deps web,data-jpa,postgresql
sprout new my-api --language kotlin --build gradle-kotlin
sprout new my-api --group com.example --artifact my-api
sprout new my-api --java 21 --boot 4.1.x
sprout new my-api --preset rest-api
sprout new my-api --git --open
sprout new my-api --deps web --dry-run # show what would happen
cd my-api
sprout add # search and pick dependencies
sprout add data-jpa postgresql # or name them
sprout remove postgresqlCheck your environment at any time:
$ sprout doctor
✓ Config ~/.config/sprout/config.toml
✓ Server https://start.spring.io (412ms, 206 dependencies, default Spring Boot 4.1.2)
✓ Cache fresh, fetched 16m ago
✓ Java 21.0.11 ~/.sdkman/candidates/java/current/bin/java
✓ Git 2.54.0 /usr/bin/git
· Maven not found (optional: Maven projects include ./mvnw)
· Gradle not found (optional: Gradle projects include ./gradlew)
· Editor not configured (set with 'sprout config set editor <cmd>' or $EDITOR)A short "how to use" for every command. Each one links to a section with more
detail. Every command also has --help, for example sprout add --help.
| Command | Use it to |
|---|---|
new |
Create a new Spring Boot project |
new class, interface, enum, record, package |
Create Java types and packages in your project |
add |
Add dependencies to an existing project |
remove |
Remove dependencies from an existing project |
deps |
Find dependency names |
versions |
See which Spring Boot versions are available |
options |
See every project option the server supports |
presets |
Save and reuse project setups |
config |
Set your defaults |
history |
See and reuse projects you generated |
cache |
Manage the cached server metadata |
doctor |
Check that everything is set up |
completion |
Turn on tab completion in your shell |
version |
Print the installed version |
Creates a new project in a new directory.
Easiest way: run sprout new and answer the questions. Use the arrow keys
to move, Enter to continue and Ctrl+C to cancel. In the dependency step,
press / to search and Space to select.
Without questions: pass the name and options as flags. Anything you leave out gets the server's default.
sprout new # wizard
sprout new my-api # wizard, name filled in
sprout new my-api --deps web,data-jpa,postgresql # no questions
sprout new my-api --build maven --java 21 --boot 4.1.x
sprout new my-api --language kotlin --build gradle-kotlin
sprout new my-api --preset rest-api # start from a saved preset
sprout new my-api --last # same settings as last time
sprout new my-api --git --open # git init, then open your editor
sprout new my-api --deps web --dry-run # only show what would happenThen cd my-api and run ./mvnw spring-boot:run (Maven) or ./gradlew bootRun
(Gradle). See Interactive mode and
Flag-based mode for every option.
Creates a Java file (or package folder) in the right place, from the
project root or any folder inside it. No need to cd into
src/main/java/com/example/....
- Run
sprout newinside your project and choose Java Class, Interface, Enum, Record or Package. - Pick the package from the list (
/to search), or + Create new package. - Type the name, check the preview, and press
Enter.
Or say it all at once:
sprout new class User --in model # com.example.demo.model.User
sprout new class controller.UserController # package in the name
sprout new interface service.UserService
sprout new enum model.UserStatus
sprout new record dto.UserResponse
sprout new package repositoryPackage names are relative to your app's base package unless fully qualified. See Creating classes, records and packages.
Adds dependencies to a project you already have, making the same build file changes start.spring.io would.
cdinto the project, or any folder inside it.- Run
sprout addand pick from the list, or name the dependencies:sprout add lombok validation. - Read the diff and answer
yto apply it. - Reload the project in your IDE.
sprout add # search and pick
sprout add web
sprout add data-jpa postgresql
sprout add datajpa # typos are corrected to data-jpa
sprout add lombok --dry-run # preview only
sprout add security --yes # skip the question (scripts)
sprout add web -C ../orders # a project in another folderIf a name isn't exact (postgres), Sprout asks "did you mean…?". See
Adding and removing dependencies.
Removes dependencies, along with anything that only they needed.
sprout rm works too.
cdinto the project.- Run
sprout removeand pick from the project's current dependencies, or name them:sprout remove lombok. - Read the diff and answer
y.
sprout remove
sprout remove lombok devtools
sprout rm web --dry-runIt takes the same flags as add: --dry-run, --yes, -C, --boot and --json.
Finds dependency IDs, the short names used by new --deps, add and
remove.
sprout deps # everything, grouped by category
sprout deps search postgres # search names and descriptions
sprout deps list --category web # one category
sprout deps info data-jpa # details, compatibility and docs links
sprout deps --boot 4.0.x # only those that work with Boot 4.0.xSee Dependency search.
Lists the Spring Boot versions the server offers and marks the default.
sprout versions
sprout versions --stable # only GA releasesPass a version to --boot as an exact version (4.1.2), a line (4.1.x) or
latest. See Spring Boot versions.
Shows every option the server supports for a new project: build types,
languages, Java versions, packaging and so on, with each one's allowed
values and default. Use it to find the values sprout new flags accept.
sprout options
sprout options --jsonSaves a set of project options under a name so you can reuse it.
sprout presets list # yours plus built-in examples
sprout presets save rest-api --java 21 --deps web,validation
sprout presets save my-usual --from-last # from the last generated project
sprout presets show rest-api # contents, checked against the server
sprout presets use rest-api my-api # = sprout new my-api --preset rest-api
sprout presets edit rest-api --java 25 # change fields
sprout presets edit rest-api # open presets.toml in your editor
sprout presets delete rest-apiSee Presets.
Sets defaults so you don't repeat the same flags. Flags you pass still take priority.
sprout config show # current settings
sprout config set default-java 21
sprout config set default-group com.acme
sprout config set default-build maven-project
sprout config set editor code # used by --open
sprout config set git true # always git init
sprout config get default-java
sprout config unset default-java
sprout config reset # back to defaults (presets are kept)
sprout config path # where the file livessprout config set --help lists every key. See Configuration.
Shows projects you generated recently. History is kept only on your machine.
sprout history # last 10
sprout history --limit 0 # all of them
sprout new another-api --last # reuse the most recent settings
sprout history clear # forget the list (your projects are untouched)Sprout caches the server's metadata (versions and dependencies) so commands start instantly. The cache refreshes by itself. These commands are for when you want control.
sprout cache status # how old the cache is
sprout cache refresh # fetch now, e.g. right after a Spring Boot release
sprout cache clear # delete itChecks your setup: config file, server connection, cache, Java, Git, Maven, Gradle and your editor. Run it first when something doesn't work.
sprout doctorPrints a tab-completion script for your shell. With completion on, Tab
suggests dependency IDs, versions, preset names and more.
sprout completion fish > ~/.config/fish/completions/sprout.fish
sprout completion zsh > "${fpath[1]}/_sprout"See Shell completion for Bash and PowerShell.
Prints the installed version. sprout --version does the same.
sprout version| Flag | Meaning |
|---|---|
--server URL |
Use a different Initializr server, such as your company's own |
--offline |
Use cached data only and never contact the server |
--no-color |
Plain output (NO_COLOR=1 works too) |
--json |
Machine-readable output, on commands that print results |
Running sprout new with no configuration flags in a terminal starts the wizard:
- Project name
- Project type, language and Spring Boot version
- Group ID, artifact ID, description, package name and project version
- Packaging, Java version and configuration file format
- Any additional options the server advertises
- Dependencies: type
/to search by name, ID or category,spaceto select; the description and Boot compatibility of the highlighted dependency are shown - Output directory
- Review, then generate
Keys: Enter/Tab next · Shift+Tab back · / search · Space select ·
Ctrl+C cancel (nothing is written).
Defaults come from the server, overridden by your configuration
and any flags or preset you pass. The artifact ID defaults to a slug of the name
(My API → my-api) and the package to <group>.<artifact> (com.example.my_api).
Only dependencies compatible with the chosen Spring Boot version are listed.
The review step validates the whole configuration and lists any problems.
--interactive/-iforces the wizard even when flags are given.--no-interactivenever prompts.- When stdin/stdout is not a terminal (pipes, CI), Sprout never prompts and requires a project name.
NO_COLORand--no-colordisable colors. SetACCESSIBLE=1for Huh's screen-reader friendly prompt mode.
Every project option has a flag, so anything you can do in the wizard can be scripted:
| Flag | Initializr field | Example |
|---|---|---|
-b, --build |
type |
maven, gradle, gradle-kotlin, or a type ID such as maven-project, gradle-project-kotlin, maven-build |
-l, --language |
language |
java, kotlin, groovy |
--boot |
bootVersion |
4.1.2, 4.1.x, 4.1, latest, 4.2.0-RC2 |
--java |
javaVersion |
21 |
-g, --group |
groupId |
com.example |
-a, --artifact |
artifactId |
my-api (defaults to the project name) |
-n, --name |
name |
"My API" (defaults to the artifact ID) |
-d, --description |
description |
"Order service" |
--package |
packageName |
com.example.orders |
--project-version |
version |
1.0.0-SNAPSHOT |
--packaging |
packaging |
jar, war |
--config-format |
configurationFileFormat |
properties, yaml |
--deps |
dependencies |
web,data-jpa (comma-separated or repeated) |
--set key=value |
any other server option | --set someOption=value |
Run sprout options to see every option the configured server supports, with its
values and defaults.
Other new flags:
| Flag | Meaning |
|---|---|
-o, --output DIR |
Project directory to create (default <output-dir>/<artifact>, where output-dir defaults to the current directory) |
--force |
Merge into a non-empty directory. Files that would be replaced are first moved to DIR/.sprout-backup-<timestamp>/; nothing is deleted |
--dry-run |
Print the resolved configuration, target directory and request URL; download and write nothing |
-p, --preset NAME |
Start from a preset |
--last |
Start from the last successfully generated configuration |
--git / --no-git |
Initialize a Git repository with an initial commit (or not, overriding config) |
--open |
Open the project in your editor (config editor, $VISUAL, then $EDITOR) |
--editor CMD |
Open with this editor command (implies --open) |
--format json / --json |
Machine-readable output (CLI output format, unrelated to --config-format) |
-i, --interactive / --no-interactive |
Force or forbid the wizard |
Precedence: server defaults < config defaults < --last < --preset < flags.
Dependencies from all layers are combined. Error messages say which layer a bad
value came from, for example java "11" (from preset "legacy") is not available.
Global flags work with every command: --server URL, --offline and --no-color.
sprout new orders --build maven --java 21 --deps web,data-jpa,postgresql \
--group com.acme --no-interactive --json | jq -r .dirRun these inside an existing Spring Boot project (any subdirectory works):
sprout add # searchable list: type / to search, space to select
sprout add web
sprout add data-jpa postgresql lombok
sprout add datajpa # typo-tolerant: uses data-jpa
sprout add "Spring Data JPA" # display names work too
sprout add postgres # not an exact ID: asks "did you mean postgresql?"
sprout remove # pick from the project's dependencies
sprout remove lombok devtools
sprout add security --dry-run # preview only
sprout add security --yes # no confirmation (scripts)
sprout add web -C ../orders # another project directoryExample:
$ sprout add lombok
./pom.xml (Maven · Spring Boot 4.1.2 · Java 21)
--- pom.xml
+++ pom.xml
@@ -36,6 +36,11 @@
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
...
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
...
Apply these changes to pom.xml? [y/N] y
✓ Added lombok to pom.xmlHow it works. Dependencies often need more than one line. Some need a test
starter, a BOM and its version property (Spring Cloud), a build plugin (native),
or annotation-processor setup (Lombok needs four Gradle configurations, or
maven-compiler-plugin configuration). Instead of guessing, Sprout:
- Reads your
pom.xml,build.gradleorbuild.gradle.ktsand detects the build type, Spring Boot version, Java version, language and packaging. - Detects which Initializr dependencies you already have, using the coordinates the server reports for each one.
- Asks Spring Initializr for your project's build file twice: as it is, and with the change.
- Applies exactly the difference to your file, element by element. Your formatting, indentation, comments, ordering and any other content are kept.
- Shows a diff and asks before writing. The file is written atomically, and only if it didn't change in the meantime.
Safety.
- Nothing is written without confirmation in a terminal, or
--yesin scripts. --dry-runonly previews.--jsonprints a machine-readable report, including the diff.- Dependencies that are already present are skipped.
- Incompatible ones are refused before anything happens (`requires Spring Boot
=4.0.0 and <4.1.0-M1, but the project uses 4.1.2`).
- If something you customized would have to change (for example your own
maven-compiler-pluginsetup when adding Lombok), Sprout leaves it alone. It prints the snippet start.spring.io would generate so you can merge it by hand. - Removing a dependency only removes what that dependency alone needs. Shared things (a BOM used by another Spring Cloud starter, for example) stay.
Typo tolerance works everywhere dependency names are accepted: add,
remove, new --deps and deps info.
- Differences in case and separators are corrected automatically, since they are
unambiguous:
datajpa,DATA_JPAandSpring Data JPAall becomedata-jpa. - Anything else, like
postgresorsecurty, opens a "did you mean…?" chooser in a terminal. In scripts it fails with suggestions instead of guessing.
Create Java types and packages without navigating into
src/main/java/com/example/.... Run these from the project root or any
folder inside the project:
sprout new # inside a project: asks what to create
sprout new class User # asks for the package (in a terminal)
sprout new class User --in model # → com.example.demo.model.User
sprout new class User --in com.example.demo.model # same thing, fully qualified
sprout new class controller.UserController # package as part of the name
sprout new interface service.UserService
sprout new enum model.UserStatus
sprout new record dto.UserResponse
sprout new package controller # → com.example.demo.controller
sprout new package admin --in controller # → com.example.demo.controller.admin
sprout new class User --in model --dry-run # preview only$ sprout new
┃ What would you like to create?
┃ > Java Class
┃ Interface
┃ Enum
┃ Record
┃ Package
┃ New Spring Boot project…
┃ Select destination package:
┃ com.example.demo
┃ > com.example.demo.controller
┃ com.example.demo.dto
┃ com.example.demo.service
┃ + Create new package
┃ Java Class name
┃ > UserController
Create class src/main/java/com/example/demo/controller/UserController.java
package com.example.demo.controller;
public class UserController {
}
Create it? [Y/n]
✓ Created class com.example.demo.controller.UserController
./src/main/java/com/example/demo/controller/UserController.javaGenerated files are minimal: just the package declaration and an empty type
(public record UserResponse() {} for records). No getters, setters or annotations.
Where files go.
- Sprout finds the project by walking up to the nearest
pom.xml,build.gradleorbuild.gradle.kts, and uses itssrc/main/javafolder. - The base package is the package of your
@SpringBootApplicationclass. If there is none, it's the common prefix of your existing packages. - A package name is relative to the base package (
controller→com.example.demo.controller) unless it is already fully qualified: it starts with the base package, names an existing package, or starts like a reverse domain (com.,org.,io., …). The base package is never duplicated. - With
--in, a package in the name is relative to it:sprout new class admin.Panel --in controller→com.example.demo.controller.admin.Panel. - Run from inside a package folder, a plain name goes into that package:
in
src/main/java/com/example/demo/model,sprout new class Addresscreatescom.example.demo.model.Address. - Missing package folders are created.
Prompts and scripts. Anything you don't give on the command line is asked for
in a terminal: the package, the name, and the module in a multi-module project.
If you were asked anything, Sprout shows a preview and asks before writing (-y
skips that). When every detail is given (sprout new class User --in model),
the file is created directly. In scripts and editor tasks without a terminal,
Sprout never prompts. A plain sprout new class User uses the base package
there, and missing information is an error. --json prints a machine-readable
result.
Multi-module projects. Run inside a module and Sprout uses that module. At
the root of a multi-module build, it asks which module, or you pass
--module api (the module's path from the root).
Safety.
- Names are checked: type names must be valid Java identifiers, not keywords or
restricted names (
var,record, …), and package names must be valid too. - Existing files are never overwritten.
- Names with
/,\or..are rejected, so nothing can be written outsidesrc/main/java. - Records need Java 16 or newer. If your build file sets an older Java version, Sprout says so.
- Cancelling (
Ctrl+C, or answeringn) writes nothing. If writing fails, folders Sprout just created are removed again. - Build files are never changed.
Zed has no right-click "New Java Class" action, but its
tasks can run Sprout in the built-in terminal.
Copy docs/zed/tasks.json to .zed/tasks.json in your
project, or to ~/.config/zed/tasks.json for every project:
[
{
"label": "Sprout: New Java type",
"command": "sprout",
"args": ["new"],
"cwd": "$ZED_WORKTREE_ROOT",
"use_new_terminal": true,
"allow_concurrent_runs": true,
"hide": "on_success"
},
{
"label": "Sprout: New Java type in current package",
"command": "sprout",
"args": ["new"],
"cwd": "$ZED_DIRNAME",
"use_new_terminal": true,
"allow_concurrent_runs": true,
"hide": "on_success"
}
]- Open the command palette, run
task: spawn, and pick a task. - "New Java type" starts from the project root and asks for everything.
- "New Java type in current package" runs in the folder of the file you're editing, so new types go into that file's package. Zed lists this task only while a file is open.
hide: "on_success"closes the terminal tab once the file is created. Remove it to keep the tab open.sproutmust be on thePATHZed's terminal uses (which sproutin that terminal).
To use a shortcut, add this to your Zed keymap (zed: open keymap):
[
{
"context": "Workspace",
"bindings": {
"ctrl-alt-n": ["task::Spawn", { "task_name": "Sprout: New Java type in current package" }]
}
}
]$ sprout deps search security
security Spring Security · Security
security-saml2 SAML 2.0 · Security
spring-security-webauthn WebAuthn for Spring Security · Security
oauth2-client OAuth2 Client · Security
...sprout deps # all dependencies, grouped by category
sprout deps list --category web # one category (case-insensitive, partial match)
sprout deps search postgres # search ID, name, description and category
sprout deps info data-jpa # description, compatibility, docs links
sprout deps --boot 4.0.x # only dependencies compatible with Boot 4.0.x
sprout deps --boot 4.0.x --all # include incompatible ones, marked
sprout deps --json # machine-readableUnknown IDs get suggestions: unknown dependency "data-jp"; did you mean data-jpa?.
$ sprout versions
4.2.0-SNAPSHOT snapshot
4.2.0-RC2 release candidate
4.1.3-SNAPSHOT snapshot
4.1.2 stable (default)
4.0.10-SNAPSHOT snapshot
4.0.9 stable
$ sprout versions --stable --jsonVersions are classified by Initializr's naming conventions: no qualifier (or
.RELEASE) is a stable GA release, -M<n> a milestone, -RC<n> a release candidate,
and -SNAPSHOT / .BUILD-SNAPSHOT a snapshot.
--boot accepts an exact version, a version line (4.1.x or 4.1) or latest. A
line resolves to its newest GA release, falling back to the newest milestone/RC and
then the newest snapshot.
Presets are named configurations stored in presets.toml in the config directory:
[presets.rest-api]
language = "java"
type = "maven-project"
packaging = "jar"
group = "com.example"
java = "21"
dependencies = ["web", "data-jpa", "postgresql"]Supported keys: type, language, boot, group, artifact, name,
description, package, version, packaging, java, config-format,
dependencies, and an [presets.<name>.extra] table for server-specific options.
See docs/presets.example.toml.
sprout presets list # your presets and built-in examples
sprout presets show rest-api # contents + validation against current metadata
sprout presets save rest-api --java 21 --deps web,validation,actuator
sprout presets save my-usual --from-last # from the last generated project
sprout presets use rest-api my-api # same as: sprout new my-api --preset rest-api
sprout presets edit rest-api --java 25 # update fields (--deps replaces the list)
sprout presets edit rest-api # open presets.toml in your editor
sprout presets delete rest-apiSprout ships five examples you can use and customize: minimal, rest-api,
web-jpa, postgres and secure-api. They are ordinary presets: saving or
editing one with the same name overrides it, and deleting your version restores
the example.
Presets are validated against the current server metadata every time they are used. If a preset refers to a Java version, Boot line or dependency that is no longer offered, Sprout explains what is outdated and does not generate a project with silently changed settings.
sprout config show
sprout config set default-language java
sprout config set default-build maven-project # alias of default-type
sprout config set default-java 21
sprout config set default-boot 4.1.x # follows new patch releases
sprout config set default-group com.example
sprout config set default-deps devtools # added to every project
sprout config set default-editor hx # alias of editor
sprout config set output-dir ~/code # parent directory for new projects
sprout config set git true # always initialize Git
sprout config set server https://start.spring.io # or your own Initializr instance
sprout config set cache-ttl 6h
sprout config get default-java
sprout config unset default-java
sprout config reset # asks first; --yes in scripts
sprout config pathRun sprout config set --help for the full list of keys.
| Linux / BSD | macOS | Windows | |
|---|---|---|---|
Config (config.toml, presets.toml) |
$XDG_CONFIG_HOME/sprout (default ~/.config/sprout) |
~/Library/Application Support/sprout |
%AppData%\sprout |
| Cache (metadata) | $XDG_CACHE_HOME/sprout (default ~/.cache/sprout) |
~/Library/Caches/sprout |
%LocalAppData%\sprout |
State (history.json) |
$XDG_STATE_HOME/sprout (default ~/.local/state/sprout) |
config dir | config dir |
Override them with SPROUT_CONFIG_DIR, SPROUT_CACHE_DIR and SPROUT_STATE_DIR.
SPROUT_SERVER overrides the configured server (the --server flag wins over both).
sprout history # recently generated projects
sprout history --json
sprout new another --last # reuse the last configuration with a new name
sprout history clear # forget history (project files are untouched)History is stored only on your machine. Sprout collects no analytics or telemetry. It talks only to the configured Initializr server.
Metadata is cached per server so commands start instantly. Cached data counts as
fresh for 12 hours by default (sprout config set cache-ttl 6h). After that it is
revalidated with an ETag conditional request.
sprout cache status
sprout cache refresh # fetch now
sprout cache clearIf the server cannot be reached, browsing commands (deps, versions, options,
presets show) fall back to cached metadata and print a warning. --offline
forces cache-only mode. Generating a project always requires the server:
the project archive is produced by Spring Initializr, so sprout new cannot work
offline. --offline --dry-run still lets you preview a configuration.
Completions include dependency IDs (also inside comma-separated --deps lists),
Boot versions and lines, Java versions, languages, project types, packaging,
configuration formats, preset names and config keys. Values come from cached
metadata, so completion is fast.
# Bash (requires bash-completion)
sprout completion bash > ~/.local/share/bash-completion/completions/sprout
# Zsh
sprout completion zsh > "${fpath[1]}/_sprout"
# Fish
sprout completion fish > ~/.config/fish/completions/sprout.fish
# PowerShell (add to $PROFILE)
sprout completion powershell | Out-String | Invoke-ExpressionRun sprout completion <shell> --help for details.
- No partial projects. The archive is downloaded into a hidden temporary
directory next to the destination, verified, extracted, and then moved into place
with a single rename. Interrupted downloads, server errors, cancellation (
Ctrl+C) and disk errors leave nothing behind. - No overwrites. A non-empty destination is refused. With
--force, Sprout merges into it. Every file that would be replaced is first moved to.sprout-backup-<timestamp>/inside the destination. If anything fails midway, all changes are rolled back. Sprout never writes through symbolic links in the destination, and it never deletes your files. - Archive hardening. Entries with absolute paths,
..segments, backslashes, drive letters or colons are rejected (ZIP Slip protection), as are symbolic links, device files and duplicate entries. Size and entry-count limits protect against ZIP bombs. Executable bits (mvnw,gradlew) are preserved. - No shell. Git and editors are started directly with argument lists, so
project names or paths cannot inject commands. Editor commands such as
code --waitare split into arguments with shell-style quoting rules.
Sprout is a client of the documented Spring Initializr API.
- Metadata is requested from the service root with
Accept: application/vnd.initializr.v2.3+json(falling back to v2.2/v2.1). Every capability is parsed generically:action(project types, with theirbuild/dialect/formattags),single-select,textand thehierarchical-multi-selectdependency tree, including defaults. - Dependency compatibility uses each dependency's
versionRange(for example[4.0.0,4.1.0-M1)) with Initializr's version ordering (M<RC<SNAPSHOT< GA). - Projects are generated with the endpoint the metadata gives for the chosen type
(
action, such as/starter.zipor/pom.xml, falling back to the HAL link). Build-file-only types (maven-build,gradle-build) write just that file. - Requests send
User-Agent: Sprout/<version> (+https://github.com/maskedsyntax/sprout; <os>/<arch>). - Any compatible Initializr instance works, including self-hosted ones under a
path prefix:
sprout config set server https://initializr.internal.example.com/start. Server-specific options appear in the wizard and insprout options, and can be set with--set.
-
Java types go in
src/main/javaonly.sprout new classand the other type commands don't support custom source folders or Kotlin/Groovy sources yet. -
The server is more lenient than Sprout. start.spring.io silently replaces some invalid values (an unsupported
javaVersion, an invalidpackageName) with defaults. Sprout validates against metadata first and reports the problem instead. If the server still rejects a request, its error message is shown verbatim. -
Compatibility is only as good as the metadata. Sprout checks the
versionRangethe server publishes. Rules that exist only on the server are reported when generation fails. -
Only capability types Sprout understands can be set. These are
text,single-select,actionand the dependency tree. If a server advertises a new kind of capability,sprout doctorreports it and it cannot be set until Sprout supports it. -
Build-file-only types (
maven-build,gradle-build) are exactly what the server offers. For example, start.spring.io has no Kotlin-DSL build-file-only type. -
No offline generation, as explained above.
-
add/removeneed a supported Spring Boot line. The server must still offer your project's Spring Boot line, because it generates the reference build files. Older projects get a clear error (--bootcan override this at your own risk). Patch versions don't matter: a 4.0.3 project uses the server's newest 4.0.x as the reference. -
add/removework on single-module projects. For multi-module builds, run them in the module that contains the Spring Boot application. Dependencies declared through a Gradle version catalog (libs.*) aren't recognized, and new ones are written as plain coordinates.
| Symptom | Fix |
|---|---|
cannot reach start.spring.io / timed out |
Check your connection or proxy. Sprout honors HTTPS_PROXY/HTTP_PROXY/NO_PROXY. Browsing commands keep working from cache. |
did not return Initializr metadata |
The server URL is not an Initializr instance (or a proxy returned HTML). Check sprout config get server. |
dependency "x" requires Spring Boot … |
Choose a compatible --boot (see sprout deps info x) or drop the dependency. |
… is not available; choose one of: … |
The value is not offered by the server (any more). Run sprout options. |
| A preset stopped working | sprout presets show <name> lists outdated values. Fix them with sprout presets edit. |
destination exists … is not empty |
Use a different --output, or --force to merge (with backups). |
| Options look outdated | sprout cache refresh. |
sprout add says a change "was customized" |
Sprout didn't overwrite your version of that element; merge the printed snippet by hand. |
sprout add can't find the project |
Run it inside the project, or pass -C <dir>. It looks for pom.xml, build.gradle or build.gradle.kts. |
| The wizard does not start | stdin and stdout must be a terminal. Use flags in scripts, or -i to force it. |
no editor configured |
sprout config set editor "code --wait" or set $EDITOR. |
| Colors are unreadable | Set NO_COLOR=1 or pass --no-color. |
sprout doctor checks connectivity, configuration, cache and local tools. Java,
Maven, Gradle and Git are optional: generated projects include build wrappers.
Requirements: Go 1.26+. No Java is needed.
make build # ./bin/sprout with version info via -ldflags
make test # unit tests (offline; a fake Initializr server is used)
make test-race
make integration # optional live test against start.spring.io
make lint # staticcheck + golangci-lint
make vet fmt
make snapshot # local GoReleaser build of all release archivescmd/sprout/ entry point (signal handling, exit codes)
internal/cli/ Cobra commands and terminal output
internal/wizard/ interactive Huh form
internal/initializr/ HTTP client (metadata, generation, errors); no UI code
internal/metadata/ metadata model, version/range logic, dependency search
internal/project/ options, layering and validation → generation request
internal/generator/ download, safe extraction, atomic placement
internal/buildfile/ format-preserving Maven/Gradle parsing, merging and diffs
internal/depedit/ add/remove: project detection and reference build files
internal/cache/ metadata cache with TTL, ETag and offline fallback
internal/config/ config.toml
internal/presets/ presets.toml and built-in examples
internal/history/ generated-project history
internal/platform/ OS directories, atomic writes, git/editor launching
internal/testutil/ fake Initializr server for tests
The metadata fixture in internal/metadata/testdata is a recorded start.spring.io
response. Refresh it with:
curl -H 'Accept: application/vnd.initializr.v2.3+json' https://start.spring.io \
| python3 -m json.tool > internal/metadata/testdata/start-spring-io-v2.3.json(Some tests assert specific versions from the fixture. Update them when refreshing it.)
Push a tag such as v0.1.0. The release workflow runs GoReleaser, which builds the
archives, checksums.txt and release notes. Homebrew cask publishing is configured in
.goreleaser.yaml, but upload is disabled until a tap repository and a
HOMEBREW_TAP_TOKEN secret exist.
Contributions are welcome. See CONTRIBUTING.md. In short:
- Open an issue for larger changes first.
- Keep the Initializr client free of UI code and avoid hardcoding server-provided values.
- Add tests (
httptest-based, no network) and runmake vet lint test. - Keep user-facing output concise and predictable.
MIT © 2026 Aftaab Siddiqui