Tomcat Launchpad
VS Code extension that compiles a Java web project, deploys it to a local Tomcat and runs it, with
per-machine profiles and per-environment overrides (for example dev and prod, both local).
No Maven, Gradle or shell scripts: everything runs from the extension on Windows and Linux.
Prerequisites
| Requirement |
Notes |
| VS Code 1.90 or later |
|
| JDK 9 or later |
Must include javac and jar. Used to compile and to run Tomcat. JDK 11 or later recommended. |
| Apache Tomcat |
A local installation (CATALINA_HOME). Tested with Tomcat 10.1. |
Debugger for Java (vscjava.vscode-java-debug) |
Only for Start Debug and Attach Debugger. The extension offers to install it. |
| JDBC driver JAR |
Only when the app uses datasources. It must be in CATALINA_HOME/lib or listed in driverJars. |
| OS keyring |
Optional. Used for datasource passwords (Windows Credential Manager, GNOME Keyring / KWallet on Linux). Without it see passwordStorage. |
Expected project layout (every folder can be changed in the profile):
<projectRoot>/
src/ Java sources and resources (srcDir)
web/ Web content: JSP, HTML, WEB-INF/web.xml (webDir)
src/main/webapp/META-INF/ Optional, copied to the webapp (metaInfDir)
build/ Output, created by the extension (buildDir)
Project JARs live in one folder (libDir), used for the compile classpath and copied to
WEB-INF/lib.
Getting started
- Open the project folder in VS Code.
- Run Tomcat Launchpad: New Profile. If the workspace has a
tasks.json that runs catalina.bat or
catalina.sh, the wizard can import JDK, Tomcat, JVM options, ports, context path and datasources
from it. Otherwise it starts empty.
- Answer the steps: profile name, project folder, JDK, Tomcat,
libDir, context path, HTTP port,
environments, environments that ask for confirmation, and datasources.
- Open the Tomcat Launchpad view in the activity bar, or click the status bar item.
- Press Start or Start Debug. Datasource passwords not stored yet are asked on the first start.
Where things are
- Activity bar view (Tomcat Launchpad > Server): active profile, environment and state, all actions
for the current state, and Start / Start Debug / Restart / Stop buttons in the view title. Click the
first row to select another profile.
- Status bar: profile, environment and state. Click it for the same menu as a quick pick.
- Terminal
Tomcat: <profile>: live Tomcat output. Closing it or pressing Ctrl+C stops the server.
- Output channel
Tomcat Launchpad: build, validation and launch messages.
- Problems panel: javac errors.
Commands
All commands are in the Command Palette under Tomcat Launchpad:.
| Command |
What it does |
| Start |
Validates, compiles, deploys and starts Tomcat. |
| Start Debug |
Same, with the JDWP agent on debugPort, and attaches the Java debugger. |
| Stop |
Sends SHUTDOWN; kills the JVM after stopTimeout seconds. |
| Restart |
Stop and start, keeping debug mode. |
| Hot Deploy |
Recompiles and syncs into the running app. With reloadable Tomcat reloads the context. |
| Attach Debugger |
Attaches to a Tomcat started in debug, or offers to restart in debug. |
| Open in Browser |
Opens http://localhost:<httpPort><contextPath>/. |
| Open Logs |
Shows the terminal or a log file that keeps updating while open. |
| Datasources |
Add, edit or remove datasources and set their passwords. |
| Set DB Password |
Changes the stored password of a datasource for the active environment. |
| Switch Environment |
Changes the active environment; offers a restart when Tomcat is running. |
| Select Profile |
Picks the active profile among those that match the workspace. |
| New Profile |
Wizard that creates a profile. |
| Edit Profiles |
Opens tomcatRunner.profiles in the user settings.json. |
| Export Profile / Import Profile |
Saves a profile to a JSON file or loads one. Passwords are never exported. |
| Build |
Compiles and copies resources to build/classes. |
| Build WAR |
Builds a WAR file with the name you choose. |
| Validate Profile |
Checks paths, JDK, Tomcat, ports and datasources. |
| Show Resolved Config |
Shows the profile merged with the active environment, variables expanded. |
| Regenerate Base |
Recreates the Tomcat instance config from CATALINA_HOME. |
| Open Base Folder |
Opens the Tomcat instance conf folder. |
| Show Menu |
Quick pick with the actions for the current state. |
Profiles
Profiles are stored in user settings (tomcatRunner.profiles) with machine scope, so Settings Sync
does not copy paths between machines. A profile applies to a workspace when its projectRoot is the
workspace folder, is inside it or contains it. The active profile and environment are remembered per
workspace.
Merge order: defaults, then profile, then environment. Scalars and arrays are replaced; maps
(systemProperties, env, attributes) are merged; datasources are merged by name.
Profile fields
Only name, projectRoot, javaHome and catalinaHome are required. Relative paths are relative to
projectRoot.
| Field |
Default |
Description |
name |
|
Unique profile name. |
projectRoot |
|
Folder of the web project. |
javaHome |
|
JDK used to compile and run Tomcat. |
catalinaHome |
|
Tomcat installation folder. |
srcDir |
src |
Java sources. |
webDir |
web |
Web content root. |
metaInfDir |
src/main/webapp/META-INF |
META-INF folder copied into the webapp. |
buildDir |
build |
Build output; classes go to build/classes. |
release |
major version of javaHome |
javac --release value, e.g. "11". |
encoding |
UTF-8 |
Source encoding for javac. |
javacArgs |
[] |
Extra javac arguments, e.g. -Xlint:unchecked. |
environments |
|
Overrides per environment, keyed by name. Without it there is one environment, default. |
Fields an environment may override
These can be set in the profile and overridden in environments.<name>.
| Field |
Default |
Description |
catalinaBase |
generated in the extension storage |
Tomcat instance folder. |
libDir |
|
JARs for the classpath, copied to WEB-INF/lib. |
libExcludes |
["jakarta.servlet-api-*.jar"] |
Glob patterns of JARs not copied to WEB-INF/lib. |
driverJars |
[] |
JDBC driver JARs copied to the Tomcat instance lib. |
contextPath |
/<profile name> |
URL path of the app. / deploys as ROOT. |
resources.include |
jaxb.index, *.properties, *.xml, *.txt, *.xsd, *.xsl, *.xslt |
Globs copied from srcDir to the classes. |
resources.exclude |
[] |
Globs excluded from the copy. |
war.name |
from contextPath, e.g. app.war |
WAR file name. |
war.includeLibs |
false |
Include libDir JARs in WEB-INF/lib of the WAR. |
httpPort |
8080 |
HTTP connector port. |
shutdownPort |
8005 |
Tomcat shutdown port. |
debugPort |
8000 |
JDWP port, on localhost only. |
debugSuspend |
false |
Wait for the debugger before starting. |
reloadable |
true |
Tomcat reloads the context when classes change. |
confirmStart |
false |
Ask for confirmation before starting. |
jvmArgs |
[] |
Extra JVM arguments, e.g. -Xmx1024m. |
systemProperties |
{} |
Passed as -Dkey=value. |
env |
{} |
Extra environment variables for Tomcat. |
datasources |
[] |
See Datasources. |
Variables
Every string field accepts:
| Variable |
Value |
${workspaceFolder} |
The workspace folder the profile matched. |
${userHome} |
The user home folder. |
${env:NAME} |
An environment variable. Fails if it is not set. |
${projectRoot} |
The resolved projectRoot (not inside projectRoot itself). |
${profile} |
The profile name. |
${environment} |
The active environment name. |
Datasources
Add them with the Datasources command or the last step of New Profile. The editor asks for the
JNDI name, the driver, the environments that use it, and the URL and user for each environment. Each
datasource becomes a <Resource> in the generated app descriptor
(conf/Catalina/localhost/<app>.xml).
| Field |
Required |
Description |
name |
yes |
JNDI name, e.g. jdbc/mainDS. |
driver |
yes |
JDBC driver class, e.g. org.postgresql.Driver. |
url |
yes |
JDBC URL. |
user |
yes |
Database user. |
sameAs |
no |
Copies another datasource by name. It shares the password unless it overrides url or user. |
type |
no |
Resource type. Default javax.sql.DataSource. |
maxTotal |
no |
Maximum open connections. Tomcat default: 8. |
maxIdle |
no |
Maximum idle connections kept in the pool. Tomcat default: 8. |
maxWaitMillis |
no |
Milliseconds to wait for a free connection. Tomcat default: -1 (wait forever). |
attributes |
no |
Any other <Resource> attribute, e.g. validationQuery. |
Optional fields that are not set are left out of the <Resource>, so Tomcat uses its own defaults.
They are edited in settings.json; the Datasources editor keeps them when it changes a datasource.
sameAs entries are also edited in settings.json.
The driver JAR must be in CATALINA_HOME/lib or in driverJars: the connection pool lives in Tomcat,
so a JAR only in WEB-INF/lib is not found. The editor asks for it when it is missing for Oracle,
PostgreSQL, MySQL, MariaDB or SQL Server, and Validate Profile warns about it.
Passwords
Passwords never go in settings or logs. They are asked once per datasource and environment on each
machine. tomcatRunner.passwordStorage decides where they are kept:
| Value |
Behavior |
auto (default) |
OS keyring. If it is unavailable, falls back to file with a one-time notice. |
keyring |
OS keyring only. Fails if it is unavailable. |
file |
Plain text in passwords.json in the extension storage and in the generated descriptor (mode 600 on Linux). |
Keyring passwords reach Tomcat as environment variables (TOMCAT_RUNNER_DB_<NAME>) and are never
written to disk.
Example
"tomcatRunner.profiles": [
{
"name": "app",
"projectRoot": "${workspaceFolder}",
"javaHome": "/opt/jdk-11",
"catalinaHome": "/opt/tomcat",
"libDir": "${userHome}/libs/app",
"driverJars": ["${userHome}/libs/app/postgresql-42.7.3.jar"],
"contextPath": "/app",
"httpPort": 8080,
"jvmArgs": ["-Xmx1024m"],
"systemProperties": { "app.config.dir": "${userHome}/config/app" },
"datasources": [
{
"name": "jdbc/mainDS",
"driver": "org.postgresql.Driver",
"maxTotal": 20,
"maxIdle": 5,
"maxWaitMillis": 10000,
"attributes": { "validationQuery": "SELECT 1" }
}
],
"environments": {
"dev": {
"datasources": [
{ "name": "jdbc/mainDS", "url": "jdbc:postgresql://localhost:5432/app_dev", "user": "app" },
{ "name": "jdbc/reportDS", "sameAs": "jdbc/mainDS" }
]
},
"prod": {
"confirmStart": true,
"reloadable": false,
"datasources": [
{ "name": "jdbc/mainDS", "url": "jdbc:postgresql://localhost:5432/app", "user": "app" },
{ "name": "jdbc/reportDS", "sameAs": "jdbc/mainDS", "user": "reports" }
]
}
}
}
]
In this example jdbc/reportDS copies jdbc/mainDS (driver, URL, pool settings). In dev it uses
the same login, so it shares the password. In prod it overrides user, so it is another login and
gets its own password.
Other settings
| Setting |
Default |
Description |
tomcatRunner.passwordStorage |
auto |
Where datasource passwords are stored. See Passwords. |
tomcatRunner.stopTimeout |
15 |
Seconds to wait for a graceful shutdown before killing Tomcat. |
How it works
- Build: full rebuild of
build/classes with javac -g (local variables visible in the debugger).
Classpath: libDir JARs, then CATALINA_HOME/lib (servlet API). Resources matching
resources.include are copied from srcDir.
- Deploy: web content, classes,
libDir JARs and META-INF are synced into the webapp folder. Only
changed files are copied; files no longer in the project are deleted.
- Tomcat instance (CATALINA_BASE): one per profile and environment, in the extension storage unless
catalinaBase is set. server.xml and the app descriptor are rewritten on every start. Other conf
files are copied once from CATALINA_HOME, and your edits to them are kept. A file not generated by
the extension is only replaced after confirmation, with a .bak copy.
- Start: Tomcat runs with
java ... org.apache.catalina.startup.Bootstrap start, with the same
flags catalina.bat/.sh add. setenv scripts are not read: use jvmArgs, systemProperties
and env. Busy ports are reported before building. The server counts as running once the HTTP port
opens, which happens after the app deploys.
- Debug: JDWP on
localhost:<debugPort>. The debugger attaches as soon as the agent is listening.
Ending the debug session leaves Tomcat running.
- Hot Deploy: with
reloadable Tomcat reloads the context within about 10 seconds; without it, web
files apply at once and a restart is offered for classes.
- Closing VS Code stops the server.
Logs
- The
Tomcat: <profile> terminal shows the live output.
- Open Logs lists the files in the instance
logs folder (newest first). They open in a read-only
editor that refreshes every second and follows the end while you are scrolled to the bottom.
catalina.out has the console output of the last start, including what the app prints with
System.out. It is rewritten on each start.
catalina.<date>.log has Tomcat's own log; localhost_access_log.<date>.txt has the HTTP requests.
Limitations
- One server per VS Code window.
setenv.bat / setenv.sh are not read.
- macOS is not tested yet.