Skip to content

Native vs container mode

Each micro in a scenario runs in one of two execution modes, and you choose it per micro:

Mode What it is When
native The micro starts as a process on your machine (with Maven, npm, uvicorn…) The micro you’re working on: fast start, hot reload, easy debugging
container The micro starts inside a Docker container Background micros: isolated, reproducible environment, without cluttering your machine

The usual combination is mixed: native for the one you develop, container for the ones you just need running for the flow to work.

In the scenario’s Cards or Table views, each micro has a native/container toggle. You can also set a micro’s default mode in its editor (Micros section).

Container mode requires Docker to be started. Native mode uses the repo’s wrapper (mvnw, .venv) or the binary on your PATH. If one is missing (JDK, Maven, Gradle, Node, Go or the .NET SDK), Aseptic installs it in its own folder (~/.aseptic/toolchains/), without admin rights and without touching the machine’s PATH: the copilot, an MCP agent or aseptic toolchain install can ask for it. The one you already have installed still takes precedence.

Native without a JDK or Maven: the tool container

Section titled “Native without a JDK or Maven: the tool container”

A Spring Boot or Quarkus service with Maven, or a Node, Go, Python or .NET service, can run in native mode without its tools on the machine (JDK and Maven, Node, Go, Python or the .NET SDK): Aseptic runs the same native command inside the official image of its stack, with the version the service asks for (maven:3.9-eclipse-temurin-<java>, node:<version> from .nvmrc or engines, golang:<version> from go.mod, python:<version> from .python-version or requires-python, the .NET SDK from the project’s TargetFramework). That is its tool container, and it is not container mode: the service stays native in everything else (its configuration, its ports, debugging).

Each service decides where its tools come from in its editor (the Tools field of the local startup configuration):

Option What it does
Automatic (default) Uses your machine’s if they are there; if one is missing and Docker is running, uses the tool container; without Docker it stays on the machine and the environment check offers to install what is missing
Machine Always your machine’s
Container Always the official image

What you already have configured comes along: your settings.xml (and settings-security.xml) read-only, the ${env.X} variables it cites and your company CA from Settings, which is added to the image’s trust. Node also gets your .npmrc; Python, your pip.conf and the PIP_INDEX_URL variables; .NET, your NuGet.Config; and Go, the variables of its module proxy (GOPROXY, GOPRIVATE…). If you cannot pull from Docker Hub, the image registry in Settings prepends the prefix of an internal mirror.

Even if you do not configure it, the container also trusts the CAs your system has beyond the default ones (the Windows store, the macOS keychain or /etc/ssl on Linux), which is where companies install the one of the proxy that inspects traffic: a service that resolves against the internal repository on your machine resolves the same way inside. In Java, the resulting store is saved and later starts just copy it. TLS verification is never turned off; if a build still does not trust a certificate, the service log explains it with a note instead of a bare PKIX.

Spring Boot and Quarkus with Gradle start with the repo’s wrapper (./gradlew bootRun or quarkusDev), without the daemon so that stopping the service also stops the application, and their configuration travels in the JAVA_TOOL_OPTIONS variable with the same -D as in Maven, without touching build.gradle. In their tool container they use the JDK image (eclipse-temurin:<java>) and a Gradle cache of their own. They are debugged just as with Maven; in Spring Boot, the debugger is added only to the application’s JVM through a Gradle init script that Aseptic passes at startup, without touching the repo.

On each start the repo is copied to a volume and built there, so there is no hot reload; dependencies go to a shared volume filled once from your ~/.m2 (the first time takes a while, and its progress shows in the log). The environment check lists the services that will go to their container and why, the card and the table mark them, and the decision is made again when the service restarts: install the JDK and it goes back to your machine.

Many development servers (uvicorn, flask run, dotnet run with its launchSettings.json, Vite) listen only on 127.0.0.1, and that port cannot be published from inside a container. For those services a minimal companion container (alpine/socat) starts next to theirs, publishes the port and forwards it to the service without touching its command; it is removed with it. Angular front ends stay on the machine: their --proxy-config is a file on your machine that does not exist inside the container. Debugging in the tool container is only available on the JVM.

Native-mode startup can be fine-tuned per micro (properties, arguments, database, command…) without touching the repo. See Customize startup.