Configuration
Platformatic Runtime is configured with a configuration file. It supports the use of environment variables as setting values with environment variable placeholders.
Configuration Files
The Platformatic CLI automatically detects and loads configuration files found in the current working directory with the file names listed here.
Alternatively, you can use the --config option to specify a configuration file path for most wattpm CLI commands. The configuration examples in this reference use the JSON format.
Supported File Formats
For detailed information on supported file formats and extensions, please visit our Supported File Formats and Extensions page.
Settings
Configuration settings containing sensitive data should be set using environment variable placeholders.
The autoload and applications settings can be used together, but at least one
of them must be provided. When the configuration file is parsed, autoload
configuration is translated into applications configuration.
autoload
The autoload configuration is intended to be used with monorepo applications.
autoload is an object with the following settings:
path(required,string) - The path to a directory containing the applications to load. In a traditional monorepo application, this directory is typically namedpackages.exclude(arrayofstrings) - Child directories insidepaththat should not be processed.mappings(object) - Each applicaiton is given an ID and is expected to have a Platformatic configuration file. By default, the ID is the application's directory name, and the configuration file is expected to be a well-known Platformatic configuration file.mappingscan be used to override these default values. Supported properties are the same of entries inapplication, exceptpath,url, andgitBranch.
preload
The preload configuration is intended to be used to register
Application Performance Monitoring (APM) agents. preload should contain
a path or a list of paths pointing to a CommonJS or ES module that is loaded at the start of
the app worker thread.
extensions
While preload injects code in each application worker thread, extensions loads custom code
in the runtime main thread. Extensions can observe and control the whole runtime: they receive
the Runtime object and an ITC (Inter-Thread Communication) facade which allows them to register
custom commands that applications can invoke from their worker threads.
extensions can be a path, an object with path and options properties, or an array of either:
{
"extensions": [
{
"path": "./runtime-extension.js",
"options": {
"bucket": "{S3_BUCKET}"
}
}
]
}
Each file must default-export a setup function, which is invoked during the runtime initialization, before any application is started. TypeScript files are supported out of the box via Node.js type stripping.
export default async function setup ({ runtime, itc, sharedContext, logger, options, root, metrics, health }) {
// React to runtime events
runtime.on('application:worker:started', payload => {
logger.info({ payload }, 'worker started')
})
// Publish state to every application worker
await sharedContext.update({ reconciler: { ready: true } })
// Register a custom command that applications can invoke via
// getITC().send('acme:hello', payload)
itc.handle('acme:hello', async payload => {
return { hello: payload.name }
})
// Register main-thread metrics with the shared Runtime metrics pipeline
const { client, registry } = metrics
const jobs = new client.Gauge({
name: 'acme_extension_jobs',
help: 'Number of jobs tracked by the extension',
registers: [registry]
})
jobs.set(0)
// Contribute readiness/liveness checks and diagnostic routes on the health probes server
health.registerReadinessCheck('dispatchable', async () => {
return { status: true }
})
health.registerLivenessCheck('control-plane', async () => true)
health.registerRoutes(async app => {
app.get('/inventory', async () => ({ ok: true }))
})
return {
async start () {
// Invoked after applications are prepared, before they accept traffic.
// Can add/start dynamic applications; Runtime will not start them again.
},
async stop () {
// Invoked during shutdown after the entrypoint stops and before remaining
// applications stop. Useful for control-plane handoff.
},
async close () {
// Invoked when the runtime is closed, after all applications have stopped.
}
}
}
The setup function receives a context object with the following properties:
-
runtime- The Runtime instance. It is anEventEmitter, so extensions can subscribe to all runtime events and invoke any public method, including application and worker introspection (getApplications(),getWorkers()), application configuration and environment (getApplicationConfig(id),getApplicationEnv(id)), and metrics (getMetrics()). -
itc- A facade over the runtime ITC:handle(name, handler)- Registers a custom command invocable from any application via the ITC API returned bygetITC()from@platformatic/globals. The name must not clash with the commands reserved by the runtime or with a command registered by another extension.send(target, name, payload)- Sends a request to a worker and awaits its response.targetis an application ID (a worker is chosen in round-robin) orapplication:worker-indexfor a specific worker.notify(target, name, payload)- Sends a fire-and-forget notification. Whentargetis an application ID, all its running workers are notified; useapplication:worker-indexto target a specific worker. Workers receive notifications viagetITC().on(name, handler).
-
sharedContext- The shared context API used by application workers.get()synchronously returns a snapshot of the current context in main-thread extensions.update(update, options?)mergesupdateinto the context and broadcasts the result to every running worker; pass{ overwrite: true }to replace the context instead. Newly started workers receive the latest context. Useupdate()rather than mutating the object returned byget(). -
logger- A child of the runtime logger. -
options- Theoptionsobject specified in the configuration, if any. -
root- The runtime project root directory. -
metrics- A per-extension Prometheus client and registry:client- The@platformatic/prom-clientmodule (same client used by application workers).registry- A dedicatedRegistryfor this extension. Metrics registered here appear once inRuntime.getMetrics(), the management metrics API, and the existing/metricsendpoint. They are not duplicated per application worker.
Label behavior: extension metrics are main-thread metrics. Runtime never invents a
workerIdor application ID label for them. Only static labels from the runtimemetrics.labelsconfiguration are applied (the configured application label name is omitted, same as process-level metrics). Extensions that need application- or worker-specific labels must set them explicitly when creating metrics.Metric family names must be unique across extensions and must not collide with runtime process metrics, restart metrics, or application worker metrics. Collisions fail with
PLT_RUNTIME_METRIC_FAMILY_COLLISION, identifying the extension and metric family. The registry is cleared when the extension closes (including partial startup failures). -
health- API for contributing readiness/liveness checks and diagnostic routes on Watt's health probes server (the metrics server when probes are shared with it, or the dedicated health probes server when configured separately):registerReadinessCheck(name, check)- Registers a named check that participates in/ready. Check names must be unique across extensions. The check may return a boolean or{ status, statusCode?, body? }. Rejected, timed-out, or malformed checks fail closed. Timeouts use the configured health checks timeout. Readiness-only failures do not fail/status(liveness), so a temporary control-plane condition can stop traffic without triggering a pod restart loop. Returns an unregister function.registerLivenessCheck(name, check)- Same contract as readiness, but the check participates in/status. Returns an unregister function.registerRoutes(plugin)- Registers a Fastify plugin on the health probes server before it starts listening. Works for shared and separate probe servers. Route collisions fail startup with a coded error identifying the extension and route. Returns an unregister function that disables the routes. Closing the extension removes its checks and routes.
The setup function can optionally return an object with awaited lifecycle hooks:
start()- Called once applications have been prepared and registered, and before the originally configured applications start accepting traffic. Runtime awaits every extensionstarthook. An extension may add and start dynamic applications here; those applications are excluded from the normal startup pass so they are not started twice. Runtime does not reportstarteduntil extension and application startup complete. If a later extension or application fails, Runtime stops and closes already-started extensions during cleanup.stop()- Called during shutdown after the entrypoint has been stopped and before the remaining applications stop. Runtime awaits every extensionstophook so control-plane extensions can settle work and hand off state.close()- Called when the runtime is being closed, after applications have stopped. The extension metrics registry is cleared afterclose.
When multiple extensions are configured, they are set up and started in registration order. stop and
close run in reverse registration order. Each of stop and close is invoked at most once per
Runtime life, including repeated stop/close calls and failed-start cleanup paths. Existing
extensions that only return close() keep their previous behavior. Health checks and routes registered
by an extension are cleaned up with it.
Listening to Runtime EventEmitter events is not a substitute for these hooks: emit() does not await
asynchronous listeners. Lifecycle ordering is enforced by Runtime itself so it covers signal handling,
internal failure cleanup, and future lifecycle entry points.
Extensions are not loaded when building the applications (for example via wattpm build).
For a complete worked example — enabling continuous profiling on every worker when it starts (or is restarted) and shipping the captured profiles — see the Capture Flamegraphs on Health Events guide.
applications
applications is an array of objects that defines the applications managed by the
runtime. Each application object supports the following settings:
-
id(required,string) - A unique identifier for the application. -
enabled(boolean,string, orobject) - Iffalse, the application is disabled and will not be loaded by the runtime. Boolean strings and environment variable placeholders are supported. It can also be an object where each key is an environment name and each value is a boolean. If the current environment does not match any key, the application is enabled. Default:true. -
path(required,string) - The path to the directory containing the application. It can be omitted ifurlis provided. -
url(required,string) - The URL of the application remote GIT repository, if it is a remote application. It can be omitted ifpathis provided. You can specify a branch using the URL fragment syntax:https://github.com/user/repo.git#branch-name. -
gitBranch(string) - The branch of the application to resolve. Takes precedence over the branch specified in the URL fragment. -
config(string) - The configuration file used to start the application. -
useHttp(boolean) - The application will be started on a random HTTP port on127.0.0.1, and exposed to the other applications via that port, on default it is set tofalse. Set it totrueif you are using @fastify/express. -
reuseTcpPorts: Enable the use of thereusePortoption whenever any TCP server starts listening on a port. The default istrue. The values specified here overrides the values specified in the runtime. -
workers- The number of workers to start for this application. If the application is the entrypoint or if the runtime is running in development mode this value is ignored and hardcoded to1. This can be specified as:number- A fixed number of workersobject- Advanced worker configuration with the following properties:static(number) - A fixed number of workersdynamic(boolean) - Enable dynamic worker scaling. This is only meaningful when set tofalseto disable dynamic scaling for this application.minimum(number) - Minimum number of workers when using dynamic scalingmaximum(number) - Maximum number of workers when using dynamic scaling
-
health(object): Configures the health check and low-level resource defaults for each worker of the application. It supports all the properties also supported in the runtime health property. The values specified here override the values specified in the runtime. -
arguments(arrayofstrings) - The arguments to pass to the application. They will be available inprocess.argv. -
envfile(string) - The path to an.envfile to load for the application. By default, the.envfile is loaded from the application directory. -
env(object) - An object containing environment variables to set for the application. Values set here takes precedence over values set in theenvfile. -
sourceMaps(boolean) - Iftrue, source maps are enabled for the application. Default:false. -
packageManager(string) - The package manager to use when using theinstall-dependenciesor theresolvecommands ofwattpm-utils. Default is to autodetect it, unless it is specified via command line. -
preload(stringorarrayofstrings): A file or a list of files to load before the application code. -
nodeOptions(string): TheNODE_OPTIONSto apply to the application. These options are appended to any existing option. -
execArgv(arrayofstrings): Additional arguments to pass to application worker threads via theexecArgvoption. These arguments are passed to the Node.js executable when creating worker threads. See Node.js Worker Threads documentation for more information. Note thatexecArgvoptions are automatically inherited by any child worker threads created by the application. -
permissions(object): Configure application-level security permissions to restrict file system access. Supported properties are:fs:read(arrayofstrings): Array of file system paths the application is permitted to read from. Uses the same syntax as Node.js --allow-fs-read.write(arrayofstrings): Array of file system paths the application is permitted to write to. Uses the same syntax as Node.js --allow-fs-write.
When filesystem permissions are enabled, certain paths are automatically added to maintain application functionality:
- The current Watt project's
node_modulesdirectory - The application's own
node_modulesdirectory - Any
node_modulesdirectories found in parent directories of the runtime path
The security permissions are based on Node.js permission model and therefore the application will have restricted access to native modules, child processes, worker threads, the inspector protocol, and WASI. See the Node.js Permission Model Constraints for complete details.
-
dependencies(arrayofstrings): A list of applications that must be started before attempting to start the current application. Note that the runtime will not perform any attempt to detect or solve dependencies cycles. -
management(booleanorobject): Grants the application access to runtime management operations via the ITC (Inter-Thread Communication) channel. See the management section for details. -
telemetry(object): containing aninstrumentationsarray to optionally configure additional open telemetry intrumentations per application, e.g.:
"applications": [
{
"id": "api",
"path": "./services/api",
"telemetry": {
"instrumentations": ["@opentelemetry/instrumentation-express"]
}
}
]
It's possible to specify the name of the export of the instrumentation and/or the options:
"applications": [
{
"id": "api",
"path": "./services/api",
"telemetry": {
"instrumentations": [{
"package": "@opentelemetry/instrumentation-express",
"exportName": "ExpressInstrumentation",
"options": {}
}]
}
}
]
An alias for applications. If both are present, their content will be merged.
It's also possible to disable the instrumentation by setting the enabled value property to false (env variables are also supported):
"applications": [
{
"id": "api",
"path": "./services/api",
"telemetry": {
"enabled": "false",
"instrumentations": [{
"package": "@opentelemetry/instrumentation-express",
}]
}
}
]
env
An object containing environment variables to set for all applications in the
runtime. Any environment variables set in the env object will be merged with
the environment variables set in the envfile and env properties of each
application, with application-level environment variables taking precedence.
envfile
The path to an .env file to load for the runtime. By default, the .env file is loaded from the application directory.
strictEnv
Controls what happens when a {PLT_*} environment variable placeholder references a variable which is not set:
false(the default): the placeholder is silently replaced with an empty string.true: loading the configuration fails at startup with an error listing all the missing variables."warn": a warning listing the missing variables is logged, but the placeholders are still replaced with an empty string.
The value is also applied when loading the configuration files of the applications in the runtime.
{
"strictEnv": true
}
sourceMaps
If true, source maps are enabled for all applications. Default: false. This setting can be overridden at the application level.
resolvedServicesBasePath
The base path, relative to the configuration file to store resolved applications. Each application will be saved in {resolvedServicesBasePath}/{id}. Default: external.
entrypoint
The Platformatic Runtime's entrypoint is an application that is exposed
publicly. This optional value must be the ID of an application defined via the autoload or
applications configuration.
If entrypoint is omitted, the runtime automatically selects one when there is a single
application or exactly one Gateway application. If it cannot select a single entrypoint,
the runtime starts without a public entrypoint; applications remain reachable through their
internal .plt.local URLs and APIs such as runtime.inject().
workers
Configures the default number of workers to start per each application. Some values can be overridden at the application level.
This can be specified as:
number- A fixed number of workers (minimum 1)object- Advanced worker configuration with the following properties:static(number) - A fixed number of workersdynamic(boolean) - Enable dynamic worker scaling (default:false). The dynamic worker scaler automatically adjusts the number of workers for each application based on Event Loop Utilization (ELU) and available system memory. It can be overridden at the application level.minimum(number) - The minimum number of workers that can be used for each application. Default:1.maximum(number) - The maximum number of workers that can be used for each application. Default: globaltotalvalue.total(number) - The maximum number of workers that can be used for all applications. Default:os.availableParallelism()(typically the number of CPU cores).maxMemory(number) - The maximum total memory in bytes that can be used by all workers. Default: 90% of the system's total memory.cooldown(number) - The amount of milliseconds the scaling algorithm will wait after making a change before scaling up or down again. This prevents rapid oscillations. Default:20000.gracePeriod(number) - The amount of milliseconds after a worker is started before the scaling algorithm will start collecting metrics for it. This allows workers to stabilize after startup. Default:30000.
This value is hardcoded to 1 if the runtime is running in development mode or when applying it to the entrypoint.
workersRestartDelay
Configures the amount of milliseconds to wait before replacing another worker of an application during a restart.
gracefulShutdown
Configures the amount of milliseconds to wait before forcefully killing an application or the runtime.
The object supports the following settings:
application(number) - The graceful shutdown timeout for an application. Default:10000(ten seconds).runtime(number) - The graceful shutdown timeout for the entire runtime. Default:30000(thirty seconds).
watch
An optional boolean, set to default false, indicating if hot reloading should
be enabled for the runtime. If this value is set to false, it will disable
hot reloading for any applications managed by the runtime. If this value is
true, then hot reloading for individual applications is managed by the
configuration of that application.
Note that watch should be enabled for each individual application in the runtime.
While hot reloading is useful for development, it is not recommended for use in production.
startTimeout
The number of milliseconds to wait before considering an application as failed to start. Default: 30000.
restartOnError
The number of milliseconds to wait before attempting to restart an application that unexpectedly exit.
If not specified or set to true, the default value is 5000, set to 0 or false to disable.
Any value smaller than 10 will cause immediate restart of the application.
This setting is ignored in production, where applications are always restarted immediately.
exitOnUnhandledErrors
When enabled (default), Platformatic automatically installs error handlers for uncaughtException and unhandledRejection events on each worker process. These handlers will automatically restart the affected worker when such errors occur.
If application code installs its own listeners for these events, Platformatic tracks them, removes them from process, and invokes them before terminating the worker. This keeps Platformatic in control of the shutdown while still allowing error reporting tools to observe fatal errors.
Set this to true to terminate the worker after 100 milliseconds. Set this to a positive number to use that number of milliseconds instead.
Setting this to false, 0, or a negative number disables the automatic error handling, making you responsible for implementing proper error handling in your application code.
health
Configures per-worker health checks and low-level worker resource defaults. Health checks are enabled only if restartOnError is greater than zero; bufferPoolSize and defaultHighWaterMark are applied during worker startup regardless.
The object supports the following settings:
enabled(boolean): If to enable the health check. Default:true.interval(number): The interval between checks in milliseconds. Default:30000.gracePeriod(number): How long after the application started before starting to perform health checks. Default:30000.maxUnhealthyChecks(number): The number of consecutive failed checks before killing the worker. Default:10.maxELU(number): The maximum allowed Event Loop Utilization. The value must be a percentage between0and1. Default:0.99.maxEventLoopDelay(number): The maximum allowed event loop delay in milliseconds. When set, each worker samples its own event loop delay (viaperf_hooks.monitorEventLoopDelay) and reports it once per second as aneventLoopDelayhealth signal; a worker whose maximum delay over a check window exceeds this value counts as unhealthy. This catches long individual stalls at low average utilization (a 150ms synchronous stall each second is an ELU of just 0.15), which are invisible tomaxELU. Disabled by default.maxEventLoopDelayP99(number): The maximum allowed p99 event loop delay in milliseconds. Same mechanism asmaxEventLoopDelay, but evaluated against the worst per-second p99 reported over the check window instead of the absolute maximum, so single outlier stalls are smoothed out. Either option activates the sampler; they can be combined. Disabled by default.maxHeapUsed(number): The maximum allowed memory utilization. The value must be a percentage between0and1. Default:0.99.maxHeapTotal(numberorstring): The maximum allowed memory allocatable by the process. The value must be an amount in bytes, in bytes or in memory units. Default:4GB.maxYoungGeneration(numberorstring): The maximum amount of memory that can be used by the young generation. The value must be an amount in bytes, in bytes or in memory units. Default:128MBcodeRangeSize(numberorstring): The maximum amount of memory that can be used for code range (compiled code). The value must be an amount in bytes or in memory units. Default:268435456(256MB).bufferPoolSize(numberorstring): Sets Node.jsBuffer.poolSizefor each application worker. The value must be an amount in bytes or in memory units. Default:262144(256KB).defaultHighWaterMark(numberorstring): Sets the default high water mark for byte streams via Node.jsstream.setDefaultHighWaterMark(false, value). The value must be an amount in bytes or in memory units. Default:262144(256KB).
bufferPoolSize is intentionally larger than the Node.js default and should be treated as an aggressive server-oriented default. Node.js pools Buffer.allocUnsafe() allocations only when size < (Buffer.poolSize >>> 1), so the 256KB default serves allocations smaller than 128KB from the pool. This covers common server allocation sizes such as HTTP parser buffers, stream chunks, and small file reads in the 4KB-64KB range, reducing allocator work and Worker-thread contention. The trade-off is one larger pool per worker/realm, and RSS can stay higher while pooled slices are retained; lower this value for memory-constrained deployments.
healthProbes
Enables the Kubernetes readiness and liveness probe endpoints. It can be a boolean, a string, or an object. Default: true.
If healthProbes is true, unset, or a string, the probe endpoints are installed on the Prometheus server. Individual probe endpoints can still be configured with metrics.readiness and metrics.liveness.
Set this to false to disable both probe endpoints globally.
Use an object to configure the health probes server. Health probes are exposed on a standalone server only when the resolved hostname and port differ from the Prometheus server. Otherwise, they are installed on the Prometheus server.
enabled(booleanorstring). Enables the health probe endpoints. Default:true.hostname(string). The hostname where the health probes server will be listening. Default:0.0.0.0.port(numberorstring). The port where the health probes server will be listening. Default:9090.readiness(objectorboolean). Optional readiness endpoint configuration. If omitted,metrics.readinessis used when present.liveness(objectorboolean). Optional liveness endpoint configuration. If omitted,metrics.livenessis used when present.
{
"metrics": {
"hostname": "0.0.0.0",
"port": 9090
},
"healthProbes": {
"hostname": "0.0.0.0",
"port": 9091,
"readiness": {
"endpoint": "/health"
},
"liveness": {
"endpoint": "/live"
}
}
}
telemetry
Open Telemetry is optionally supported with these settings:
applicationName(required,string) — Name of the application as will be reported in open telemetry. In theruntimecase, the name of the applications as reported in traces is${applicationName}-${applicationId}, whereapplicationIdis the id of the application in the runtime.version(string) — Optional version (free form)skip(array). Optional list of operations to skip when exporting telemetry definedobjectwith properties:method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACEpath. e.g.:/documentation/json
exporter(objectorarray) — Exporter configuration. If not defined, the exporter defaults toconsole. If an array of objects is configured, every object must be a valid exporter object. The exporter object has the following properties:type(string) — Exporter type. Supported values areconsole,otlp,zipkin,memory, andfile(default:console).memoryis only supported for testing purposes.options(object) — These options are supported:url(string) — The URL to send the telemetry to. Required forotlpexporter. This has no effect onconsole,memory, andfileexporters.headers(object) — Optional headers to send with the telemetry. This has no effect onconsole,memory, andfileexporters.path(string) — The path where spans are written when using thefileexporter.protocol(string) — OTLP transport protocol. Supported values arehttpandgrpc. Defaults tohttp.transport(string) — Alias forprotocol. Supported values arehttpandgrpc. Defaults tohttp.
diagLogger(boolean) — Enable the OpenTelemetry diagnostic logger. Diagnostic messages are forwarded to the Platformatic global logger using the current logger level.
basePath
The base path for the Platformatic Runtime. Set it when your application is deployed under a subpath, for example, /api.
The runtime will automatically strip the base path from the incoming requests.
{
"telemetry": {
"applicationName": "test-application",
"diagLogger": true,
"exporter": {
"type": "otlp",
"options": {
"url": "http://localhost:4318/v1/traces"
}
}
}
}
httpCache
The httpCache configuration is used to enable the HTTP cache for the Platformatic Runtime.
It can be a boolean or an object with the following settings:
store(string) - The store to use for the cache. Set an npm package name to use a custom store or path to a file to use a custom store from a file. By default, thememorystore is used.methods(array) - The HTTP methods to cache. By default, GET and HEAD methods are cached.cacheTagsHeader(string) - The header to use for cache tags.maxCount(integer) - The maximum number of entries in the cache.maxSize(integer) - The maximum size of the cache in bytes.maxEntrySize(integer) - The maximum size of a single entry in the cache in bytes.origins(array) - Whitelist of origins to cache. Only requests to these origins will be cached. Supports exact string matches and regex patterns. To use a regex, wrap the pattern in forward slashes (e.g.,"/https:\\/\\/.*\\.example\\.com/").cacheByDefault(integer) - Default cache duration in milliseconds for responses that don't have explicit expiration headers (likeCache-ControlorExpires). If not set, responses without explicit expiration will not be cached.type(string) - The type of cache. Can be"shared"(default) or"private". A shared cache may store responses that can be shared between users, while a private cache is dedicated to a single user. Note thats-maxagedirective only applies to shared caches, whilemax-ageapplies to both.