---
title: "Update a project"
method: PUT
path: "/v1/projects/{projectId}"
tags: ["Projects"]
---

# Update a project

`PUT /v1/projects/{projectId}`

## Request

- Base URL: `https://api.spice.ai`
- URL: `https://api.spice.ai/v1/projects/{projectId}`
- Auth: HTTP bearer

Updates a project's metadata and configuration, including description, visibility, spicepod configuration, replicas, and resource limits.

## Path parameters

- `projectId` integer, required

## Headers

- `X-Org-Name` string

## Request body

- object
  - `description` string
  - `visibility` 'public' | 'private'
  - `production_branch` string
  - `tags` object: Key-value tags for the project. The map replaces the stored tags. System tags the project already has stay on the project when the map omits them.
  - `spicepod` union: The project's Spicepod. A project connected to a GitHub repository takes its Spicepod from the repository's spicepod.yaml, so for such a project only the stored Spicepod, sent back unchanged, is accepted.
    - string: YAML string of the spicepod configuration
    - object: JSON object of the spicepod configuration
  - `image_tag` string, nullable: Runtime image tag for a managed project; rejected for standalone projects. A non-empty value pins the project. On stable, the pin must be a published stable runtime version. On preview, it must be a published preview or stable runtime version. On stable or preview, send null to clear a pin so deploys resolve from the channel catalog (stable - latest GA for the configured version range; preview - latest RC). null is rejected on nightly and internal channels.
  - `update_channel` 'stable' | 'preview' | 'nightly': Update channel for a managed runtime; rejected for standalone projects.
  - `version` string: Semver range for a managed runtime version (e.g. 1.x, 2.x); rejected for standalone projects.
  - `replicas` integer: Managed runtime replica count; rejected for standalone projects.
  - `resources` object: Resource requests and limits for a managed project container; rejected for standalone projects.
    - `limits` object
      - `cpu` string: Whole-number vCPU limit, or '-' for no CPU limit
      - `memory` string: Memory limit in Gi (for example, 16Gi)
      - `ephemeral-storage` string: Ephemeral storage limit in Gi (for example, 8Gi)
    - `requests` object
      - `cpu` string: CPU request. Minimum 100 millicores (for example, 100m or 0.1).
  - `executor` object: Executor container configuration for a managed project; rejected for standalone projects.
    - `replicas` integer: Number of executor replicas
    - `resources` object: Resource requests and limits for the executor container
      - `limits` object
        - `cpu` string: Whole-number vCPU limit, or '-' for no CPU limit
        - `memory` string: Memory limit in Gi (for example, 16Gi)
        - `ephemeral-storage` string: Ephemeral storage limit in Gi (for example, 8Gi)
      - `requests` object
        - `cpu` string: CPU request. Minimum 100 millicores (for example, 100m or 0.1).
    - `storage_size_gb` number
  - `region` string: Managed project region; standalone placement is resolved during attachment.
  - `cluster_name` string: Reassign the project to a dedicated cluster, as listed by `GET /v1/clusters`. Provide at most one of `region` or `cluster_name`. When set, region/routing are derived from the cluster; if `region` is also provided it must match the cluster's region. Rejected for standalone projects, whose placement is resolved during attachment.
  - `storage_size_gb` number: Managed runtime storage size; rejected for standalone projects.
  - `storage_claim_size_gb` number: Deprecated. Use storage_size_gb instead. Rejected for standalone projects.

## Response `200`

Project updated successfully

- ProjectWithConfig
  - `id` integer: Unique identifier for the project
  - `name` string: Name of the project
  - `kind` 'managed' | 'standalone' | 'byoc': Resolved project hosting model
  - `description` string, nullable: Description of the project
  - `visibility` 'public' | 'private': Visibility setting for the project
  - `created_at` string, date-time: Timestamp when the project was created
  - `cname` string, nullable: Region identifier
  - `cluster_name` string, nullable: Resolved dedicated cluster name; null for projects not assigned to a dedicated cluster.
  - `endpoint` string, nullable: The data-plane endpoint the project connects to, or null before a standalone instance is attached.
  - `production_branch` string, nullable: Production branch for the project
  - `api_key` string: Deprecated. Use the API Keys endpoints instead.
  - `tags` object, nullable: Key-value tags for the project
  - `forked_from` object, nullable: The project this project was forked from, while that project is live in the same organization. Null for a project that was not created as a fork.
    - `id` integer, required: ID of the source project
    - `name` string, required: Name of the source project
  - `paused_at` string, date-time, nullable: Timestamp when the project was paused; null while running
  - `warning` string, nullable: Present when the project was created but initial configuration could not be applied
  - `config` object, nullable: Runtime configuration; null for an unattached standalone project.
    - `spicepod` object, nullable: Spicepod configuration
    - `registry` string, nullable: Container registry for the runtime image
    - `image_tag` string, nullable: Runtime image tag
    - `update_channel` 'stable' | 'preview' | 'nightly' | 'null', nullable: Update channel for the runtime
    - `replicas` integer: Number of replicas
    - `resources` object, nullable: Resource requests and limits for the project container
      - `limits` object
        - `cpu` string: Whole-number vCPU limit, or '-' for no CPU limit
        - `memory` string: Memory limit in Gi (for example, 16Gi)
        - `ephemeral-storage` string
      - `requests` object
        - `cpu` string: CPU request. Minimum 100 millicores (for example, 100m or 0.1).
    - `executor` object, nullable: Executor container configuration
      - `replicas` integer: Number of executor replicas
      - `resources` object: Resource requests and limits for the executor container
        - `limits` object
          - `cpu` string: Whole-number vCPU limit, or '-' for no CPU limit
          - `memory` string: Memory limit in Gi (for example, 16Gi)
          - `ephemeral-storage` string
        - `requests` object
          - `cpu` string: CPU request. Minimum 100 millicores (for example, 100m or 0.1).
    - `region` string, nullable: Cloud region code (e.g., us-east-1)
    - `node_group` string, nullable: Node group for scheduling the project runtime
    - `storage_claim_size_gb` number, nullable: Storage claim size in GB

## Other responses

- `400`: Invalid request body or project ID, including placement or hosted runtime fields that do not apply to standalone projects. When `image_tag` is supplied on stable or preview, a tag that is not a published version for that channel returns `{ error: 'Invalid image_tag for stable channel', code: 'invalid_stable_image_tag' }` (or the preview analog). A `spicepod` that adds a component on a source the Spice runtime no longer loads returns code `retired_component_source`; components the project already stores on such a source may be kept, edited and renamed, and a project backed by a GitHub repository is not checked. A `spicepod` that adds a plain-text secret (a password, token, API key, private key, or URL password in a component param) returns code `plaintext_secrets` with `plaintext_secrets` listing each path. Store the value as a project or org secret and use `${secrets:NAME}` in its place. Secrets the stored spicepod already holds do not block the update.
- `401`: Unauthorized
- `403`: Insufficient scope, viewer role cannot mutate projects, requested replicas or resources exceed plan limits, dedicated-cluster assignment or special-org private-compute ceilings required, requested resources exceed dedicated-cluster capacity, `image_tag` was supplied outside the Enterprise plan (code: `image_tag_requires_enterprise`), or the requested runtime image is not available for the organization plan (code: `image_tag_not_allowed_for_plan`); omitting `image_tag` leaves the configured image unchanged
- `404`: Project not found
- `409`: The project's lifecycle state changed while the update was in flight (a pause, resume, or restore landed at the same time), so the configuration was not saved (code: `project_state_changed`). Re-read the project before retrying: a configuration update clears `paused_at`, so repeating this request against a project that has since been paused also resumes it. Or a `spicepod` that differs from the stored one was sent for a project connected to a GitHub repository (code: `github_connected`); change spicepod.yaml in the repository instead, since nothing in that request is applied.
- `500`: Internal server error
- `502`: The configuration was stored but could not be published to the spicepod registry (code: `registry_publish_failed`), so the project still deploys its previously published configuration. Retry the request.
- `503`: Runtime version catalog is unavailable

---

[API](https://skmtc.dev/spice/apis/spice-cloud-control-plane-api.md) - [All operations](https://skmtc.dev/spice/apis/spice-cloud-control-plane-api/llms.txt) - [OpenAPI document](https://skmtc.dev/spice/apis/spice-cloud-control-plane-api/revisions/5f3b75dd847d?raw)
