diff --git a/reference/configuration/operations.md b/reference/configuration/operations.md
index 38c20edd..75d9ed69 100644
--- a/reference/configuration/operations.md
+++ b/reference/configuration/operations.md
@@ -16,7 +16,7 @@ For the full list of configurable options, see [Configuration Options](./options
## Set Configuration
-Modifies one or more Harper configuration parameters. **Requires a [restart](../operations-api/operations.md#restart) or [restart_service](../operations-api/operations.md#restart_service) to take effect.** A change to `replication.threads` takes effect only on a full `restart`.
+Modifies one or more Harper configuration parameters. **Requires a [restart](../operations-api/operations.md#restart) or [restart_service](../operations-api/operations.md#restart_service) to take effect** (a [restart](../operations-api/operations.md#restart) for `threads.v8Flags`). A change to `replication.threads` takes effect only on a full `restart`.
`operation` _(required)_ — must be `set_configuration`
@@ -82,6 +82,8 @@ To restart the whole cluster afterward, follow with [restart_service](../operati
}
```
+`restart_service` restarts only worker threads, which keep the process's V8 flags. A change to [`threads.v8Flags`](./options.md#applying-v8-flags) takes effect only after a [restart](../operations-api/operations.md#restart), sent to each node in turn.
+
---
## Get Configuration
diff --git a/reference/configuration/options.md b/reference/configuration/options.md
index 837c0b61..d1212841 100644
--- a/reference/configuration/options.md
+++ b/reference/configuration/options.md
@@ -68,6 +68,7 @@ threads:
- `debug` — Enable Node.js inspector; sub-options: `port`, `startingPort`, `host`, `waitForDebugger`. See [Worker Thread Debugging](./debugging.md)
- `preload` — Module, or list of modules, to load via Node's `--import` before any Harper or application module on each worker thread. Intended for instrumentation and APM agents. Worker threads only (not under Bun).
- `preloadRequire` — The same, but via Node's `--require` (CommonJS). Worker threads only (not under Bun).
+- `v8Flags` — V8 flag, or list of V8 flags, applied to the whole Harper process before its first worker thread starts. Each entry must start with `--`. Takes effect on process start. Not applied under Bun. See [Applying V8 flags](#applying-v8-flags)
### Preloading an instrumentation agent
@@ -105,6 +106,24 @@ threads:
The dd-trace behavior described here was observed on 6.x. Check your agent's current documentation, and confirm your spans arrive at your collector.
+### Applying V8 flags
+
+Some V8 flags, such as `--optimize-for-size`, cannot be passed through `NODE_OPTIONS` (Node refuses them there) or to a worker thread. `v8Flags` applies them inside Harper instead: the main thread calls Node's [`v8.setFlagsFromString()`](https://nodejs.org/api/v8.html#v8setflagsfromstringflags) for each entry before the first worker thread starts, so every worker thread runs with them. V8 flags are process-wide, so they also affect the main thread from that point on. The main thread's isolate already exists, though, so flags V8 reads only when an isolate is created (such as heap sizing) do not change it. With `count: 0`, the main thread serves requests, so those creation-time flags do not affect request handling; flags V8 reads while running still apply.
+
+```yaml
+threads:
+ v8Flags:
+ - --optimize-for-size
+ - --max-semi-space-size=1
+```
+
+The value can also be set from the environment, for example `HARPER_SET_CONFIG='{"threads":{"v8Flags":["--optimize-for-size","--max-semi-space-size=1"]}}'`.
+
+- **Validation.** Surrounding whitespace is trimmed, and an empty entry is ignored. An entry that does not start with `--` is refused by `set_configuration`, and stops Harper at startup with an error naming `threads.v8Flags`. V8 skips a flag it does not recognize and only prints `Error: unrecognized flag` to standard error, so check the spelling against your Node version (`node --v8-options`).
+- **Implied flags are not applied.** On the command line, some flags turn on others; `--optimize-for-size` also caps the young-generation semi-space at 1 MB. Applied at runtime, a flag does not do that, so list the implied flags explicitly, as the example does with `--max-semi-space-size=1`.
+- **When it takes effect.** Flags are read once per process. A changed value takes effect when the whole process restarts: the [`restart`](../operations-api/operations.md#restart) operation, which restarts only the node that receives it, or a process or container restart. [`restart_service`](../operations-api/operations.md#restart_service) restarts only worker threads, which keep the process's flags, so it does not apply a change, even with `"replicated": true`. To roll back, remove the setting from `HARPER_SET_CONFIG` or `HARPER_CONFIG` if it came from there, and from `harper-config.yaml` (for example `set_configuration` with `"threads_v8Flags": null`), then restart the process. A `THREADS_V8FLAGS` environment variable is written into `harper-config.yaml` at every startup, so unset it as well; unsetting the variable alone leaves the flags in the file.
+- **Expert setting.** Flags change V8's behavior for the whole process and are not validated beyond the `--` prefix. A conflicting combination can stop the process at startup. Measure memory and throughput with your workload before relying on a flag in production.
+
---
## `authentication`
diff --git a/reference/operations-api/operations.md b/reference/operations-api/operations.md
index 2911fb92..b31687fb 100644
--- a/reference/operations-api/operations.md
+++ b/reference/operations-api/operations.md
@@ -1688,7 +1688,7 @@ Detailed documentation: [Configuration Overview](../configuration/overview.md)
Updates configuration parameters in `harper-config.yaml`. A restart (`restart` or `restart_service`) is required for changes to take effect.
-Supports `"replicated": true` to apply the same change to all cluster nodes in one call; per-node outcomes are returned in the response's `replicated` array. Only send cluster-appropriate parameters when replicating — node-local parameters (ports, `node.hostname`, file paths, TLS material, `replication.hostname`/`url`/`routes`) would overwrite every peer's local values. To apply the change cluster-wide, follow with `restart_service` using `"replicated": true` (which restarts nodes one at a time). See [Configuration Operations](../configuration/operations.md#set-configuration) for details.
+Supports `"replicated": true` to apply the same change to all cluster nodes in one call; per-node outcomes are returned in the response's `replicated` array. Only send cluster-appropriate parameters when replicating — node-local parameters (ports, `node.hostname`, file paths, TLS material, `replication.hostname`/`url`/`routes`) would overwrite every peer's local values. To apply the change cluster-wide, follow with `restart_service` using `"replicated": true` (which restarts nodes one at a time); `restart_service` restarts only worker threads, though, so a change to [`threads.v8Flags`](../configuration/options.md#applying-v8-flags) takes effect only after a `restart` sent to each node in turn (`restart` does not replicate). See [Configuration Operations](../configuration/operations.md#set-configuration) for details.
```json
{
diff --git a/release-notes/v5-lincoln/5.4.md b/release-notes/v5-lincoln/5.4.md
index e684c1b5..e1f63819 100644
--- a/release-notes/v5-lincoln/5.4.md
+++ b/release-notes/v5-lincoln/5.4.md
@@ -51,3 +51,9 @@ A `deploy_component` with `restart: true` or `restart: "rolling"` now checks its
### Setting Up GitHub Actions Deploys
`harper deploy setup=true provider=github-actions` sets a cluster up so a GitHub Actions workflow can deploy with its OIDC identity token instead of a stored credential. It creates a deploy-only role and user, a trust policy matching the workflow's repository, branch and environment, and the repository's `HARPER_CLI_TARGET` variable. It checks the policy against the workflow file in the repository's checkout before it writes, where it can, and reads it back after. It only creates: running it again leaves the cluster and the variable as they are, a record that differs, or that someone deactivated or disabled, stops it before it writes, and a `HARPER_CLI_TARGET` that names another cluster is left in place. A policy with the same id that another super user creates in the moment before setup writes it is still overwritten. See [GitHub Actions deploys (OIDC)](/reference/v5/cli/commands#github-actions-deploys-oidc).
+
+## Configuration
+
+### Applying V8 Flags From the Configuration
+
+The new `threads.v8Flags` setting takes a V8 flag, or a list of them, and applies them to the Harper process before its first worker thread starts, so every worker thread runs with them. It is for flags such as `--optimize-for-size`, which Node refuses in `NODE_OPTIONS` and which cannot be passed to a worker thread. It can also be set through `HARPER_SET_CONFIG` or `HARPER_CONFIG`. An entry must start with `--`; `set_configuration` refuses one that does not, and Harper stops at startup with an error naming the setting. Unlike the command line, this does not apply a flag's implied flags, so list them yourself (for example `--max-semi-space-size=1` alongside `--optimize-for-size`). A changed value takes effect when the process restarts (the `restart` operation, on each node); `restart_service` restarts only worker threads and does not apply it. Not applied under Bun. See [Applying V8 flags](/reference/v5/configuration/options#applying-v8-flags).