# Deploy to Deno Deploy

**Goal:** push a NetScript workspace to [Deno Deploy](https://deno.com/deploy) with a single first-class command — `netscript deploy deno-deploy <op>` — preflighting it for the hosted platform, pushing a preview, promoting to production, and reading status and logs, without hand-rolling a `deno deploy` invocation.

This is the one **runnable managed-platform** path in NetScript today. It is a thin router over the native `deno deploy` CLI: NetScript resolves your `deploy.targets['deno-deploy']` config, layers any flags on top, runs an unstable-API guard, and shells out to `deno deploy`. Authentication, upload, and the platform itself are all owned by the `deno deploy` CLI — NetScript adds the preflight and the config-to-argv wiring, nothing more.

> This is the managed-platform path; the container/VM path is still manual
>
> netscript deploy deno-deploy
>
> is fully wired and runnable. The Docker, Compose, and Linux/systemd targets are
>
> config schema only
>
> — there is no runnable
>
> netscript deploy docker|compose|linux
>
> verb yet. For those targets you assemble the deployment yourself from the primitives in the
>
> Deploy
>
> recipe.

## Before you start

**What you need before your first push**

| Name | Type | Description |
| --- | --- | --- |
| `A healthy workspace` | `netscript init` | A workspace that passes `deno task check`. If you have not built one, start with [Quickstart](https://rickylabs.github.io/netscript/quickstart/). |
| `The deno deploy CLI on PATH` | `external CLI` | NetScript shells out to `deno deploy …`. The `deploy` subcommand ships with a current Deno; confirm `deno deploy --help` resolves before you start. |
| `A Deno Deploy account + auth` | `deno deploy login` | Authentication is delegated entirely to the `deno deploy` CLI — its own token/login flow. NetScript issues no credentials and stores no token. Log in with the CLI (or supply its auth env vars) first. |
| `An organization + app name` | `org / app` | The Deno Deploy organization slug and the application/project name to deploy into. Provide them as config or flags (below). |

> Where the command lives (and where it does not)
>
> The surface is the CLI subcommand
>
> netscript deploy deno-deploy
>
> , wired inside
>
> packages/cli
>
> . There is
>
> no
>
> @netscript/deploy
>
> package and no rollback, secrets, or health-gating command — those are described in the deployment doctrine as a future wave, not shipped. Document and rely on only the five operations below.

## Configure the target (`deploy.targets['deno-deploy']`)

Set defaults once in `netscript.config.ts` under `deploy.targets['deno-deploy']`. Every field is optional — you can pass everything as flags instead — but config keeps a repeatable push to one line.

```ts
// netscript.config.ts
export default {
  deploy: {
    targets: {
      "deno-deploy": {
        org: "my-org",          // Deno Deploy organization slug  → deno deploy --org
        app: "my-app",          // application / project name      → deno deploy --app
        entrypoint: "main.ts",  // default "main.ts"               → positional arg to deno deploy
        prod: false,            // default false; true adds --prod
        envFile: ".env.production", // passed as `--env-file <path>` to deno deploy
      },
    },
  },
};
```

**deploy.targets['deno-deploy'] fields (all optional)**

| Name | Type | Description |
| --- | --- | --- |
| `org` | `string` | Deno Deploy organization slug. Forwarded as `--org`. |
| `app` | `string` | Application / project name. Forwarded as `--app`. |
| `entrypoint` | `string` | Module the platform runs. Defaults to `main.ts`. Passed as the positional argument to `deno deploy`. |
| `prod` | `boolean` | Defaults to `false` (preview). When `true`, the push adds `--prod`. |
| `envFile` | `string (path)` | Environment file path. Passed straight through as `--env-file <path>` to `deno deploy` (see the callout below). |

> envFile is `--env-file`, not `deno deploy env load`
>
> Some older docstrings describe
>
> envFile
>
> as being "loaded via
>
> deno deploy env load
>
> ". The shipped adapter does
>
> not
>
> call
>
> env load
>
> ; it appends
>
> --env-file <path>
>
> to the
>
> deno deploy
>
> invocation. Treat the value as a path to a
>
> .env
>
> -style file that
>
> deno deploy
>
> reads directly.

> Flags win over config
>
> Config is the default layer; command-line flags override it per run. Nothing in config is required — a fully flag-driven push (
>
> --org … --app … --entrypoint …
>
> ) works with no
>
> deploy
>
> block at all. This is what lets one workspace target several orgs/apps from different pipelines without editing
>
> netscript.config.ts
>
> .

## The workflow: plan → preview → production

The command exposes five operations. All five share the same resolution flags; `up` adds two more.

**netscript deploy deno-deploy**

| Name | Type | Description |
| --- | --- | --- |
| `plan` | `preflight` | Runs the unstable-API guard only. Never touches the platform. Reports whether the project is Deploy-ready or lists violations. |
| `up` | `push` | Runs the guard, then shells `deno deploy [--prod] …`. Adds `--prod` (promote to production) and `--dry-run` (equivalent to `plan`; does not push). |
| `status` | `read` | Maps to `deno deploy show` to read deployment state. Live-account behavior is pending verification. |
| `logs` | `read` | Shows deployment logs (`deno deploy logs`). |
| `down` | `delete` | Maps to `deno deploy delete` to remove the deployment. Live-account behavior is pending verification. |

**Shared flags (all subcommands) + up-only flags**

| Name | Type | Description |
| --- | --- | --- |
| `--org ` | `shared` | Organization slug. Overrides `org` from config. |
| `--app ` | `shared` | Application / project name. Overrides `app`. |
| `--entrypoint ` | `shared` | Entrypoint module. Overrides `entrypoint` (default `main.ts`). |
| `--env-file ` | `shared` | Env file forwarded as `--env-file` to `deno deploy`. Overrides `envFile`. |
| `--project-root ` | `shared` | Workspace root to resolve config + the guard against. Defaults to the discovered root or the current directory. |
| `--prod` | `up only` | Promote this push to production. Without it, `up` pushes a preview. |
| `--dry-run` | `up only` | Run the preflight without pushing — the same effect as `plan`. |

A typical first deployment walks these steps:

```bash
# Guard-only. No push, no platform mutation. Safe to run any time.
netscript deploy deno-deploy plan --org my-org --app my-app

# Equivalent, via up:
netscript deploy deno-deploy up --dry-run --org my-org --app my-app
```

```bash
# Push a preview deployment (no --prod). If the guard finds unstable-API
# usage it warns but still proceeds for a preview.
netscript deploy deno-deploy up --org my-org --app my-app
```

```bash
# Promote to production. If the guard finds unstable-API usage, this
# REFUSES to push (see the guard callout).
netscript deploy deno-deploy up --prod --org my-org --app my-app
```

```bash
# Read state and logs, or delete the deployment.
netscript deploy deno-deploy status --org my-org --app my-app
netscript deploy deno-deploy logs   --org my-org --app my-app
netscript deploy deno-deploy down   --org my-org --app my-app
```

If your `netscript.config.ts` already carries the `org`/`app`/`entrypoint`, every line above shortens to just `netscript deploy deno-deploy <op>` — the config supplies the rest, and any flag you add wins for that run.

## The unstable-API guard

Before any push, NetScript runs a best-effort **unstable-API guard**. Deno Deploy rejects `--unstable-*` flags, so a project that depends on an unstable API cannot run there — the guard catches this before you upload rather than after the platform rejects it.

**Signatures the guard scans for**

| Name | Type | Description |
| --- | --- | --- |
| `Deno.openKv` | `--unstable-kv` | Deno KV usage. |
| `Deno.cron` | `--unstable-cron` | Deno cron scheduling. |
| `new BroadcastChannel` | `--unstable-broadcast-channel` | Cross-isolate broadcast channels. |
| `Temporal.` | `--unstable-temporal` | The Temporal API. |

> up --prod refuses when the guard finds a violation
>
> The guard reads
>
> deno.json#unstable
>
> plus the entrypoint source (
>
> <root>/<entrypoint>
>
> and
>
> <root>/src/<entrypoint>
>
> —
>
> not
>
> the full module graph). Behavior on a match:
>
> - **`up --prod`** — **refuses** and throws. Deno Deploy would reject the required `--unstable-*` flag, so a KV/cron/broadcast/Temporal project is blocked from production until you remove the dependency or move it off the entrypoint path.
> - **`up` (preview)** — **warns but proceeds**.
> - **`plan` / `up --dry-run`** — reports the violations and exits without pushing.
>
> Because the scan is entrypoint-scoped and best-effort, a clean
>
> plan
>
> is a strong signal, not a proof: an unstable API reached only through a deep import may not be flagged.

Many NetScript runtime plugins (workers, sagas, triggers) require Deno KV and therefore `--unstable-kv`. Those background processors are not a fit for a single Deno Deploy isolate — deploy a KV-free entrypoint (for example a Fresh app or a stateless oRPC service) here, and run the KV-backed processors on infrastructure that permits `--unstable-kv`, as covered in the [Deploy](https://rickylabs.github.io/netscript/how-to/deploy/) recipe.

## Troubleshooting

**Common failures and what they mean**

| Name | Type | Description |
| --- | --- | --- |
| `deno deploy: command not found` | `PATH` | The native `deno deploy` CLI is not resolvable. NetScript only shells out to it. Confirm `deno deploy --help` works in the same shell. |
| `Auth / 401 on push` | `auth` | Authentication is the `deno deploy` CLI's own flow — NetScript stores no token. Log in with the CLI (or provide its auth env vars) and retry. |
| `up --prod throws about unstable APIs` | `guard` | The guard found `Deno.openKv`/`Deno.cron`/`BroadcastChannel`/`Temporal`. Deploy a KV-free entrypoint, or move the unstable usage off the entrypoint path. |
| `Wrong org/app targeted` | `precedence` | Flags override config. Check for a stale `deploy.targets['deno-deploy']` default, or pass `--org`/`--app` explicitly. |
| `env vars not applied` | `env-file` | The value is passed as `--env-file <path>` to `deno deploy`, not `deno deploy env load`. Confirm the path exists and is a `.env`-style file. |
| `down / status behaves unexpectedly` | `platform` | The `deno deploy show`/`delete` subcommands `status`/`down` map to are not yet verified against a live Deno Deploy account, so their exact argv and behavior are pending live-account verification. NetScript isolates the argv in one adapter, so any upstream change is a framework-side fix, not a config error. |

## Where to go next

[Deploy (containers & bare metal)  The manual path: deployable units from appsettings.json, backing services, per-process deno run commands, and the --no-aspire escape hatch.](https://rickylabs.github.io/netscript/netscript/how-to/deploy/)

[Deploy locally with Aspire  Run the whole graph on one machine under the Aspire AppHost before you ship anything remote.](https://rickylabs.github.io/netscript/netscript/how-to/deploy-local-aspire/)

[Add OpenTelemetry  Wire spans and traceparent propagation to your OTLP collector so a deployed process is observable.](https://rickylabs.github.io/netscript/netscript/how-to/add-opentelemetry/)

For every CLI command grouped by workflow, see the [CLI reference](https://rickylabs.github.io/netscript/cli-reference/).
