Skip to content

Configuration ⚙️

Almost all runtime behavior is controlled through one YAML file: src/main/resources/config.yaml. mangoo I/O loads it with SnakeYAML, flattens the nested keys into dot notation, and exposes them through the Config class and Guice @Named bindings. There is deliberately no second configuration mechanism (no properties files, no XML, no @ConfigurationProperties classes to keep in sync); if a setting exists, it lives in this one file, which makes it realistic to actually read the whole configuration of an application in one sitting.

Typical uses include connector host and port, cookie names, MongoDB connection details, SMTP settings, feature toggles (admin UI, metrics, scheduler), and security options (CORS, authentication redirects). Sensitive values should reference the vault, environment variables, or JVM properties rather than plain text in the repository, since config.yaml normally ends up committed to source control.

The file is split into a default block (shared by all modes) and an environments block with overrides for dev, test, and prod. When the application starts, it merges default with the section for the active mode, key by key, so a key you only set in default still applies everywhere, and a key you also set under environments.prod overrides it just for production. Missing an environment section for the active mode causes startup to fail on purpose. That may feel strict the first time it happens, but it exists to catch the case where someone adds a staging environment, forgets to add matching config, and the app would otherwise silently fall back to defaults in a place where nobody is watching.

Values are addressed with dot notation that mirrors the YAML hierarchy:

application:
  api:
    key: foo
config.getString("application.api.key");

You can point the application at a different file entirely by setting the JVM property application.config to an absolute path, which is handy for a config file that lives outside the JAR in production (see Operating).

Accessing configuration

Inject io.mangoo.core.Config. Constructor injection is preferred, mostly because it makes Config show up in your test setup explicitly instead of being pulled in behind the scenes:

import io.mangoo.core.Config;
import jakarta.inject.Inject;

public class MyService {
    private final Config config;

    @Inject
    public MyService(Config config) {
        this.config = config;
    }
}

Look up values by key string, or by the constants in io.mangoo.constants.Key if you would rather avoid typos in raw strings scattered across the codebase:

config.getString("application.api.key");
config.getString(Key.APPLICATION_API_KEY);

Typed helpers also exist (getInt, getLong, getBoolean) and dedicated getters such as getApplicationName() or getSmtpHost() for the values the framework itself relies on.

Every entry in config.yaml is also bound as a Guice @Named string, so a class that only needs one particular value can ask for exactly that, rather than pulling in the whole Config object:

@Inject
public MyService(@Named("application.named") String named) {
    // ...
}

Modes

mangoo I/O has three modes: dev, test, and prod. The mode decides which environments.<mode> block gets merged into default, so switching modes is really just switching which overrides apply, not a different code path.

  • dev is activated by mvn mangooio:run.
  • test is activated when tests start the application through TestRunner.
  • prod is the default when you start the packaged JAR, so you do not need to set anything special for a normal deployment.

Set the mode explicitly with a system property, useful when you want prod-like behavior locally to reproduce something:

java -Dapplication.mode=dev -jar myapp.jar

or, less common outside of tooling that starts the JVM itself:

System.setProperty("application.mode", "dev");

Environment-specific values

Put shared settings under default and overrides under environments.<mode>. The active mode overwrites matching keys from default, leaving everything else untouched:

default:
  application:
    name: myapp
    url: http://localhost

environments:
  test:
    application:
      url: https://test.example.com
  prod:
    application:
      url: https://example.com

Here application.name stays myapp in every mode, since none of the environment blocks touch it, while application.url changes depending on where the app is actually running.

The active environment block is required, even if it only overrides a single key. If environments.dev (or test / prod) is missing entirely, startup fails rather than quietly falling back to default alone.

Secrets, environment variables, and JVM arguments

Configuration values can also come from the application vault, environment variables, or JVM arguments instead of being written out in plain text. See Secrets for how vault{}, env{}, and arg{} placeholders are resolved.

As a rule of thumb: cookie signing keys, the vault password, and SMTP credentials should never sit in source control as clear text, since config.yaml is versioned right alongside your application code and gets the same read access as everything else in the repository.

Connectors

At least one HTTP or HTTPS connector must be configured, otherwise the application refuses to start. There is no implicit default port, on purpose: a web framework that silently picks a port for you is more surprising than one that asks you to say so once.

default:
  connector:
    http:
      host: localhost
      port: 8080
    https:
      host: localhost
      port: 8443
      certificate:
        alias: certificate

HTTPS uses an SSL context built from the vault. The certificate alias defaults to certificate, which only matters if you store more than one certificate in the same keystore.

Default values

Keys that you omit fall back to the defaults below. Cells marked (none) have no built-in default, meaning the feature stays off or the value stays empty until you set it yourself. MongoDB keys are nested under persistence in YAML (persistence.mongo.host, and persistence.<prefix>.mongo.host for additional named datastores, see Persistence).

Key Description Default
application.admin.enable Enables the admin dashboard false
application.admin.locale Locale for the admin dashboard en_EN
application.admin.password Admin dashboard password (none)
application.admin.secret Admin TOTP secret; if set, MFA is required (none)
application.admin.username Admin dashboard username (none)
application.allowedOrigins Comma-separated origins for OriginFilter (none)
application.api.key Shared secret for ApiKeyFilter (none)
application.controller Controller package prefix controllers.
application.language Default application language en
application.name Application name (JWT issuer, logs) mangooio-application
application.named Example named Guice binding (none)
application.parameter.strict Reject requests whose query parameter collides with a route parameter with a 400 false
application.secret Application secret; fallback for cookie keys (none)
application.timezone Application timezone UTC
application.validation.passthrough Return Bean Validation errors as JSON instead of a rendered form false
application.vault.enable Enable the PKCS12 vault (none)
application.vault.path Directory of vault.p12 in prod (none)
application.vault.secret Vault password (min. 64 characters) (none)
authentication.blacklist Enable authentication blacklist cache false
authentication.cookie.name Authentication cookie name mangooio-auth
authentication.cookie.key JWT signing key; falls back to application.secret (none)
authentication.cookie.secret JWT encryption secret; falls back to application.secret (none)
authentication.cookie.remember.expires Remember-me lifetime in seconds 2592000
authentication.cookie.samesitemode SameSite attribute Strict
authentication.cookie.secure Secure cookie flag false
authentication.cookie.token.expires Token and cookie lifetime in seconds 3600
authentication.lock Failed logins before lockout 10
authentication.origin Append ?origin= on auth redirects false
authentication.redirect.login Redirect when authentication is missing (none)
authentication.redirect.mfa Redirect when MFA is required (none)
connector.http.host HTTP bind address (none)
connector.http.port HTTP port (none)
connector.https.host HTTPS bind address (none)
connector.https.port HTTPS port (none)
connector.https.certificate.alias Vault certificate alias certificate
cors.alloworigin Regex for Access-Control-Allow-Origin ^http(s)?://(www\.)?example\.(com\|org)$
cors.enable Send CORS headers false
cors.headers.allowcredentials Access-Control-Allow-Credentials true
cors.headers.allowheaders Access-Control-Allow-Headers Authorization,Content-Type,Link,X-Total-Count,Range
cors.headers.allowmethods Access-Control-Allow-Methods DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
cors.headers.exposeheaders Access-Control-Expose-Headers Accept-Ranges,Content-Length,Content-Range,ETag,Link,Server,X-Total-Count
cors.headers.maxage Access-Control-Max-Age 864000
cors.urlpattern Regex of request URLs that receive CORS headers ^http(s)?://([^/]+)(:([^/]+))?(/([^/])+)?/api(/.*)?$
flash.cookie.name Flash cookie name mangooio-flash
flash.cookie.key Flash JWT signing key (none)
flash.cookie.secret Flash JWT encryption secret (none)
i18n.cookie.name Locale cookie name mangooio-i18n
metrics.enable Collect request metrics for the admin dashboard false
otlp.enable Enable OpenTelemetry export false
otlp.endpoint OTLP gRPC endpoint (none)
persistence.enable Enable MongoDB persistence true
persistence.mongo.auth Use MongoDB authentication false
persistence.mongo.authdb MongoDB authentication database (none)
persistence.mongo.dbname MongoDB database name mangoo-io-mongodb
persistence.mongo.embedded Start embedded MongoDB false
persistence.mongo.host MongoDB host localhost
persistence.mongo.password MongoDB password (none)
persistence.mongo.port MongoDB port 27017
persistence.mongo.username MongoDB username (none)
scheduler.enable Enable @Run scheduling true
session.cookie.expires Persist the session cookie beyond the browser session false
session.cookie.name Session cookie name mangooio-session
session.cookie.key Session JWT signing key (none)
session.cookie.secret Session JWT encryption secret (none)
session.cookie.samesitemode SameSite attribute Strict
session.cookie.secure Secure cookie flag (also used for flash) false
session.cookie.token.expires Session token lifetime in seconds 3600
smtp.authentication Enable SMTP authentication false
smtp.debug Enable SMTP debug output false
smtp.from Default From address mangoo <noreply@mangoo.local>
smtp.host SMTP host localhost
smtp.password SMTP password (none)
smtp.port SMTP port 25
smtp.protocol SMTP protocol smtps
smtp.username SMTP username (none)
undertow.maxentitysize Maximum HTTP entity size in bytes 4194304

A couple of these are worth calling out by name. authentication.cookie.samesitemode and session.cookie.samesitemode both default to Strict, which is the safest choice against CSRF but also means the cookie will not be sent on cross-site navigations at all (a link from another domain, for instance); loosen it to Lax if your login flow depends on that. undertow.maxentitysize caps request body size at 4 MiB by default, mostly to stop an accidental (or malicious) huge upload from eating memory before your controller even gets a chance to reject it; raise it deliberately if your application genuinely needs larger uploads.