Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
17a9058
feat(config): add the [workers] section to the project config schema
johnstonmatt Aug 18, 2026
0b1b9b3
feat(cli): add supabase workers new
johnstonmatt Aug 18, 2026
69c83d2
feat(config): add the [workers] section to the project config schema
johnstonmatt Aug 18, 2026
81cfd54
Merge branch 'FUNC-753/workers-config' of https://github.com/supabase…
johnstonmatt Aug 25, 2026
9c5cd2d
Merge branch 'develop' of https://github.com/supabase/cli into FUNC-7…
johnstonmatt Aug 25, 2026
2ea6b94
fix(config): let the Go config loader accept the [workers] section
johnstonmatt Aug 25, 2026
3408a66
test(config): add workers.ts to the pure runtime graph allowlist
johnstonmatt Aug 25, 2026
66a8383
Merge branch 'FUNC-753/workers-config' into FUNC-753/workers-new
johnstonmatt Aug 25, 2026
d50c763
fix(cli): import loadProjectConfig from the effect entrypoint
johnstonmatt Aug 25, 2026
58302a4
refactor(cli): read Option through its public helpers in workers
johnstonmatt Aug 25, 2026
59707a6
docs(cli): give the first workers new example its required name
johnstonmatt Aug 25, 2026
93bcf8e
docs(cli): stop pointing users at a [workers] root that no longer exists
johnstonmatt Aug 25, 2026
32d265f
docs(cli): describe the shipped refusal semantics in workers new SIDE…
johnstonmatt Aug 25, 2026
fb04deb
fix(cli): keep workers new out of config.json
johnstonmatt Aug 25, 2026
72ec632
Merge remote-tracking branch 'origin/develop' into FUNC-753/workers-new
johnstonmatt Aug 25, 2026
81e864e
fix(workers): pin config loader to workdir with search: false
johnstonmatt Aug 26, 2026
39ae31b
Merge branch 'develop' into FUNC-753/workers-new
kanadgupta Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@
"ignore": [
"scripts/*.ts",
"tests/**/*.ts",
"src/shared/telemetry/event-catalog.ts"
"src/shared/telemetry/event-catalog.ts",
"src/shared/workers/stacks/**"
],
"ignoreBinaries": [
"nx",
Expand Down
2 changes: 2 additions & 0 deletions apps/cli/src/legacy/cli/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { legacyStorageCommand } from "../commands/storage/storage.command.ts";
import { legacyTestCommand } from "../commands/test/test.command.ts";
import { legacyTelemetryCommand } from "../commands/telemetry/telemetry.command.ts";
import { legacyUnlinkCommand } from "../commands/unlink/unlink.command.ts";
import { legacyWorkersCommand } from "../commands/workers/workers.command.ts";
import { legacyVanitySubdomainsCommand } from "../commands/vanity-subdomains/vanity-subdomains.command.ts";
import { OutputFormatFlag } from "../../shared/cli/global-flags.ts";
import { outputLayerFor } from "../../shared/output/output.layer.ts";
Expand Down Expand Up @@ -70,6 +71,7 @@ export const legacyRoot = Command.make("supabase").pipe(
legacyDomainsCommand,
legacyEncryptionCommand,
legacyFunctionsCommand,
legacyWorkersCommand,
legacyGenCommand,
legacyInitCommand,
legacyInspectCommand,
Expand Down
64 changes: 64 additions & 0 deletions apps/cli/src/legacy/commands/workers/new/SIDE_EFFECTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# `supabase workers new [name]`

> **Local-disk only.** Nothing is deployed and no Management API route is
> called; `workers push` is what talks to the platform.

## Files Read

| Path | Format | When |
| ---------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- |
| `<workdir>/supabase/config.toml` | TOML | always, to refuse a worker that is already recorded |
Comment thread
johnstonmatt marked this conversation as resolved.
Outdated
| `<destination>/` | dir | always, to refuse a destination that is not empty |
Comment thread
johnstonmatt marked this conversation as resolved.
| `<SUPABASE_HOME or ~/.supabase>/profile` | plain text | when neither `--profile` nor `SUPABASE_PROFILE` is set — names the profile, defaulting to `supabase` |
Comment thread
kanadgupta marked this conversation as resolved.
| `<SUPABASE_PROFILE>` (YAML) | YAML | when `SUPABASE_PROFILE` is a filesystem path rather than a built-in name; a read failure aborts the command |
Comment thread
kanadgupta marked this conversation as resolved.

## Files Written

| Path | Format | When |
| ----------------------------------------------- | ------ | ------------------------------------------------------------------------- |
| `<workdir>/supabase/config.toml` | TOML | always — appends/updates `[workers.<name>]` in place, preserving comments |
Comment thread
johnstonmatt marked this conversation as resolved.
Outdated
| `<workdir>/supabase/workers/<name>/*` | varies | always, unless `--source` names another directory |
| `<workdir>/<source>/*` | varies | when `--source` is given |
Comment thread
johnstonmatt marked this conversation as resolved.
Outdated
| `<SUPABASE_HOME or ~/.supabase>/telemetry.json` | JSON | always — flushed on success and on failure |

Nothing at the destination is ever removed or overwritten: a destination that
exists and is not empty is refused, and clearing it is left to the user.
`--source` is refused when it resolves to the project root, `supabase/`,
`supabase/functions/`, `supabase/migrations/`, or outside the project. Symlinks
are resolved first, so a path inside the project that points outside it is
refused too. A relative `--source` is resolved against the directory the command
was run in; a `source` recorded in `config.toml` is resolved against the project
root.

## API Routes

| Method | Path | Auth | Request body | Response (used fields) |
| ------ | ---- | ---- | ------------ | ---------------------- |
| — | — | — | — | — |

## Exit Codes

| Code | Condition |
| ---- | --------------------------------------------------------------------- |
| `0` | success |
| `1` | invalid or reserved worker name, unknown runtime/size, bad `--source` |
| `1` | destination exists and is not empty |
| `1` | `config.toml` records a worker in a form that cannot be edited safely |

## Environment Variables

| Variable | Purpose | Required? |
| ----------------------- | ---------------------------------------------------- | ------------------------------------------------------- |
| `SUPABASE_ACCESS_TOKEN` | auth token (bypasses credential file/keyring lookup) | no (falls back to keyring → `~/.supabase/access-token`) |
Comment thread
kanadgupta marked this conversation as resolved.
Outdated
| `SUPABASE_PROFILE` | built-in profile name or YAML file path | no (falls back to `~/.supabase/profile` -> `supabase`) |
| `SUPABASE_WORKDIR` | project directory the command acts on | no (falls back to `--workdir`, then the ancestor walk) |
Comment thread
kanadgupta marked this conversation as resolved.
Outdated
| `SUPABASE_HOME` | directory holding `telemetry.json` | no (falls back to `~/.supabase`) |

## Telemetry Events Fired

| Event | When | Notable properties / groups |
| ---------------------- | ------------------------------------------ | ----------------------------------- |
| `cli_command_executed` | post-run, success or failure (via wrapper) | `exit_code`, `duration_ms`, `flags` |

No custom events — only the `cli_command_executed` that the instrumentation
wrapper emits for every command.
Comment thread
johnstonmatt marked this conversation as resolved.
Comment thread
johnstonmatt marked this conversation as resolved.
74 changes: 74 additions & 0 deletions apps/cli/src/legacy/commands/workers/new/new.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Layer } from "effect";
import { Argument, Command, Flag } from "effect/unstable/cli";
import type * as CliCommand from "effect/unstable/cli/Command";
import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts";
import { commandRuntimeLayer } from "../../../../shared/runtime/command-runtime.layer.ts";
import { WORKER_RUNTIMES, WORKER_SIZES } from "../../../../shared/workers/worker-runtimes.ts";
import { legacyCliConfigLayer } from "../../../config/legacy-cli-config.layer.ts";
import { legacyDebugLoggerLayer } from "../../../shared/legacy-debug-logger.layer.ts";
import { legacyTelemetryStateLayer } from "../../../telemetry/legacy-telemetry-state.layer.ts";
import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts";
import { legacyWorkersNew } from "./new.handler.ts";

const config = {
name: Argument.string("name").pipe(
Argument.withDescription("Worker name. Doubles as its directory, and its hostname."),
),
runtime: Flag.choice("runtime", WORKER_RUNTIMES).pipe(
Comment thread
johnstonmatt marked this conversation as resolved.
Flag.withDescription(
"Runtime to scaffold and record in supabase/config.toml. Prompted when omitted.",
),
Flag.optional,
),
size: Flag.choice("size", WORKER_SIZES).pipe(
Flag.withDescription(
"Instance size to record in supabase/config.toml. Each size implies its own vCPU count, so there is no separate --cpu. Prompted when omitted.",
),
Flag.optional,
),
source: Flag.string("source").pipe(
Flag.withDescription(
"Scaffold the worker here instead of the default workers directory, recorded as `source` in supabase/config.toml.",
),
Flag.optional,
),
} as const;

export type LegacyWorkersNewFlags = CliCommand.Command.Config.Infer<typeof config>;

const cliConfig = legacyCliConfigLayer.pipe(Layer.provide(legacyDebugLoggerLayer));

/** Local-disk only: no Management API, so no platform stack is built. */
const legacyWorkersNewRuntimeLayer = Layer.mergeAll(
cliConfig,
legacyTelemetryStateLayer,
commandRuntimeLayer(["workers", "new"]),
);

export const legacyWorkersNewCommand = Command.make("new", config).pipe(
Command.withDescription(
"Scaffold a worker directory from a runtime's starter files and record the choice in supabase/config.toml. Nothing is deployed.",
),
Command.withShortDescription("Scaffold a worker locally"),
Command.withExamples([
{
command: "supabase workers new",
description: "Scaffold a worker, prompting for runtime and size",
Comment thread
johnstonmatt marked this conversation as resolved.
Outdated
},
{
command: "supabase workers new api --runtime node",
description: "Scaffold supabase/workers/api on the node runtime",
},
{
command: "supabase workers new api --source packages/api",
description: "Scaffold the worker outside the workers directory",
},
]),
Command.withHandler((flags) =>
legacyWorkersNew(flags).pipe(
withLegacyCommandInstrumentation({ flags, config }),
withJsonErrorHandling,
),
),
Command.provide(legacyWorkersNewRuntimeLayer),
);
Loading
Loading