# Production

URL: https://docs.domainruntime.dev/docs/environments/production
Status: Planned
Reviewed: 2026-09-23



<div className="docs-note">
  **Releases run in production today**

   as immutable builds of your domain source, created through the platform. 

  `druntime push`

   releases your folder's domain; building straight from a Git commit and rollback from the CLI are 

  **planned**

  .
</div>

A production environment runs a **release**: your domain and action code, built once, immutable. A development session never touches production; a release is an explicit `druntime push` to the production environment.

## Create the environment [#create-the-environment]

```bash
druntime env create main --project orders --mode prod --client-org acme
```

Its handle is `prod-acme-main` and its URL `https://prod-acme-main.domainruntime.cloud`. Set the project's repository, branch and root directory when you create the project (`druntime project create orders --repository … --branch main`) or in the console.

## Release [#release]

```bash
druntime push --env prod-acme-main
```

1. The CLI uploads your domain's source from your folder (see [Releasing to production](/docs/platform/cli#releasing-to-production)).
2. The platform builds your domain and action code. A failed build shows the compiler's messages at your files' paths.
3. It applies your schema, checked against the stored data first. A change the data does not allow, or an unconfirmed removal, stops the release and nothing is applied. See [Changing the schema](/docs/data/modeling-data#changing-the-schema).
4. It activates the release. New calls run the new code; calls already in flight finish on the old one.

The release records the digest of the built code, the schema it applied, and who pushed it and made it live.

**Who can release:** an owner or admin of the organization, signed in as themselves, or the organization's [service key](/docs/auth/service-keys) from CI. The first release also sets up the environment's runner with a credential valid for that environment only; nobody handles it, and the organization's key never leaves the platform.

## Making safe changes [#making-safe-changes]

When a release activates, browsers that loaded your app before it are still open, and workflows started before it are still running. Change things so both keep working.

| Change        | Safe                                            | Unsafe                                              |
| ------------- | ----------------------------------------------- | --------------------------------------------------- |
| Action input  | add an optional field                           | add a required field, narrow a type, rename a field |
| Action output | add a field                                     | remove or rename a field an old client reads        |
| Actions       | add a new action                                | rename or remove one that old clients call          |
| Schema        | add an entity, attribute or link                | change or remove an attribute (refused on release)  |
| Workflows     | change code; running runs stay on their release | —                                                   |

To make an unsafe change, do it in steps: add the new shape, release, move clients to it, then remove the old one in a later release.

## Roll back [#roll-back]

```bash
druntime release rollback --env prod-acme-main
```

Rollback re-activates the previous release's code. It does not revert data or schema — one more reason to only ever *add* to the schema in a release.

## Delete an environment [#delete-an-environment]

```bash
druntime env delete prod-acme-main    # type the handle to confirm
```

It stops serving at once and its data is kept for 2 days: `druntime env restore prod-acme-main` brings the environment back with its data and its last release. While custom domains still point at it, it is not deleted without `--force`. See [Deleting an environment](/docs/platform/cli#deleting-an-environment).

## Before you ship [#before-you-ship]

* Every entity has explicit rules and the default is deny: `$default: { allow: { $default: "false" } }`. See [Permissions](/docs/auth/permissions).
* Every action checks its caller at the top of `execute`. See [Actions](/docs/data/actions#who-may-call-an-action).
* Your backend mints user tokens. See [Users](/docs/auth/users).
* Actions that create things take a caller-chosen id or write through a `.unique()` attribute. See [Guarantees](/docs/data/guarantees).
