pier_

pier.yaml

Every key of the project file — top level, environments, and each resource kind

pier.yaml declares a project: its environments and, per environment, every resource. pier apply converges the platform to it; pier deploy also builds and rolls (Apply and deploy). The file is found by walking up from the current directory (CLI configuration).

pier.yaml
version: 1
name: acme                  # display name
project: acme-8fb4          # slug, generated at pier config init — do not edit
vcs:                        # written by pier github connect
  provider: github
  repo: acme-inc/acme
  auto_deploy: true
templates:                  # reusable target fragments, applied with `use:`
  web:
    replicas: 2
environments:
  prod:
    protected: true
    env:
      LOG_LEVEL: { value: info }
    apps: [  ]
    sites: [  ]
    postgres: [  ]
    buckets: [  ]
    volumes: [  ]
  staging:

Top level

KeyTypeMeaning
versionint1
namestringdisplay name
projectstringthe project slug; generated
workspacestringoptional; pins the workspace when a user belongs to several
vcsobjectprovider (github), repo (owner/name), auto_deploy (default true), commit_status (default true) — GitHub
templatesmapnamed fragments (replicas, autoscale, dockerfile) a target or app pulls in with use:; expanded by the CLI before anything reaches the platform
environmentsmapslug → environment; each is a complete, independent declaration (Concepts)

Environment

KeyTypeMeaning
namestringdisplay name (default: the slug)
protectedboolpier dev asks before pulling this environment's secrets; the console marks it
envmapvariables at environment scope — Environment variables
apps, sites, postgres, buckets, volumesliststhe resources

Variables (env)

env:
  LOG_LEVEL:    { value: info }
  API_KEY:      { secret: true }
  DATABASE_URL: { from: postgres.main.url }
  OPTIONAL:     { value: "1", required: false }

value · secret · from (postgres.<name>.url|host|port|user|password|database, buckets.<name>.url|name|endpoint|access_key|secret_key) · required (default true). Allowed at environment, app/site and target scope; the narrowest wins.

App

apps:
  - name: api
    build_context: ./api         # or targets[].image
    template: node_hono          # starter, instead of build_context
    env: {  }
    previews:
      enabled: true
      branch_pattern: "feat/*"
      plan: app-s
      ttl_hours: 72
      max_targets: 5
      env: {  }
    targets:
      - name: primary
        primary: true
        use: web                 # a template
        plan: app-s
        replicas: 2              # or autoscale
        autoscale:
          min: 1
          max: 3
          idle_after: 10m        # with min 0: scale to zero
          triggers:
            - { type: cpu, target: 70 }
            - { type: latency, target_ms: 250 }
        image: traefik/whoami:v1.10.1   # static-image flow; exclusive with build_context
        port: 80                        # required with image; default 8080 for builds
        dockerfile: Dockerfile.worker
        deploy:
          branch: main                  # or branch_pattern
        domains:
          - host: api.acme.example
        volumes:
          - { volume: data, mount_path: /var/lib/app }
        env: {  }

Trigger types: cpu, memory (target percent), rps (target requests per second per instance), latency (target_ms). Apps · Plans.

Site

sites:
  - name: www
    build_context: ./www
    template: site_astro
    env: {  }
    previews: {  }              # as for apps, without plan
    targets:
      - name: primary
        primary: true
        framework: vite          # vite · nextjs-static · astro · sveltekit-static · hugo · static · custom
        build_command: npm run build
        output_dir: dist
        index_document: index.html
        spa_fallback: true
        routes:
          redirects: [ { source: /old, destination: /new, status: 308 } ]
          rewrites:  [ { source: /api/*, destination: /v2/* } ]
          headers:   [ { path: /assets/*, headers: { Cache-Control: "public, max-age=31536000" } } ]
          fallback:  { type: spa, paths: [/app/*], exclude: [/api/*], document: index.html }
        deploy: { branch: main }
        domains: [ { host: www.acme.example } ]
        env: {  }

Sites.

Postgres

postgres:
  - name: main
    targets:
      - name: primary
        version: "17"
        plan: pg-s
        replicas: 1
        bootstrap_default_database: app
        max_storage_gb: 50

Exactly one target per environment. Postgres.

Bucket

buckets:
  - name: uploads
    access: private              # or public

Buckets.

Volume

volumes:
  - name: data
    storage_gb: 5
    durability: standard         # or ha; set at creation

Mounted by an app target's volumes: binding. Volumes.

Validation

pier config validate checks the file without a server call: syntax, names, that every from: names a resource in the same environment, that image and build_context are not both set, that replicas and autoscale are not both set, one Postgres target per environment. pier apply --dry-run shows what the platform would change.