# Set up a staging environment

> A second, complete environment beside prod — its own apps, Postgres and variables — and how to work in it

URL: https://pier.run/docs/guides/set-up-a-staging-environment

**Goal.** `acme` has a `staging` environment with its own copy of `api` and its own
Postgres, deployed from the same repository.

### Add the environment

```bash
pier environments add staging
```

```text title="output"

  Changes:
    + create environment "staging" (new environment)

→  Updated pier.yaml
OK  Created environment "staging"

```

An environment starts empty. It does not inherit from `prod`: each environment is a
complete declaration ([Concepts](/docs/concepts#environment)).

### Copy what should exist there

```bash
pier copy app api --to staging
```

```text title="output"
OK  Copied app "api" to pier.yaml (staging)

```

`copy` writes the app's declaration (plan, targets, variable declarations) into the
`staging` block of `pier.yaml`. Custom domains are not copied, because a hostname belongs
to one target. Secret values are not copied; set them for staging with `pier vars set …
-e staging`. Postgres, buckets and volumes hold data, so they are declared explicitly
rather than copied:

```yaml title="pier.yaml"
  staging:
    apps:
      - name: api
        build_context: ./api
        targets:
          - name: primary
            plan: app-s
    postgres:
      - name: main
        targets:
          - name: primary
            version: "17"
            plan: pg-s
            bootstrap_default_database: app
```

The block is a declaration; nothing exists on the platform until it is deployed:

```bash
pier deploy -e staging
```

```text title="output"
→  Comparing staging environment against platform state...

  Changes:
    + create app "api" in staging (plan: app-s, replicas: 1)

  Deploy:
    app "api"    reuse — no build (content unchanged)

OK  Applied 1 config change(s) to staging
→  Building api from ./api
→  Building pier-build/api:latest...

→  Pushing registry.pier.run/01a05313-e4fa-7707-a014-05f1ae901cec/api:9eed0df...
9eed0df: digest: sha256:722f9d0debe5e0de80eccf3bac4ed714cb6ef9e6e8177b5301329c4a7042c4b9 size: 855
OK  Pushed registry.pier.run/01a05313-e4fa-7707-a014-05f1ae901cec/api:9eed0df
→  Deploying api...
→  Waiting for infrastructure provisioning...
OK  Infrastructure ready

OK  Summary: 1 built, 1 deployed

```

### Work in it

```bash
pier use staging
```

```text title="output"
OK  Switched to environment staging

```

Every command now acts on `staging` until `pier use prod`. For one command only, `-e`:

```bash
pier deploy -e staging
pier ls -e staging
```

```text title="output"

  Apps
                                                                                       
 NAME STATUS  REPLICAS AUTOSCALE IMAGE                                    PORT UPDATED 
                                                                                       
 api  running 1/1      -         zot.pier-registry.svc.cluster.local:5... 8080 5m ago  
                                                                                       

```

## What changed

```yaml title="pier.yaml"
version: 1
name: acme
project: acme-1ab0
environments:
    prod:
        apps:
            - name: api
              build_context: ./api
              env:
                API_KEY:
                    secret: true
                DATABASE_URL:
                    from: postgres.main.url
                LOG_LEVEL:
                    value: info
              targets:
                - name: primary
                  plan: app-s
                  replicas: 1
                  domains:
                    - host: api.acme.example
        sites:
            - name: www
              build_context: ./www
              targets:
                - name: primary
        postgres:
            - name: main
              targets:
                - name: primary
                  version: "17"
                  plan: pg-s
                  bootstrap_default_database: app
        buckets:
            - name: uploads
    staging:
        name: staging
        apps:
            - name: api
              build_context: ./api
              targets:
                - name: primary
                  plan: app-s
                  replicas: 1

```

## Variations

* **Deploy staging from a branch**: connect GitHub and set the staging target's trigger
  to `develop` ([Deploy from GitHub](/docs/guides/deploy-from-github)).
* **Previews instead of a whole environment**: a branch preview is a target inside
  `prod` that shares its Postgres ([Preview deployments](/docs/guides/preview-deployments)).
  Use staging when the data must be separate.
* **Pause when idle**: `pier environments pause staging` stops it; `resume` restarts it
  with its data.

## See also

[`pier environments`](/docs/cli/reference/environments) · [`pier use`](/docs/cli/reference/use) ·
[`pier copy`](/docs/cli/reference/copy) · [Concepts: environment](/docs/concepts#environment)
