cloudgrid.yaml reference
cloudgrid.yaml is the manifest at the root of your project. It declares the
services your entity runs, the infrastructure it needs, and how it behaves.
grid new creates it; grid plug reads it to build and deploy.
The file is portable — it carries no identity and no secrets — so it is safe to
commit. The .cloudgrid/ folder (which does hold identity) is gitignored.
Minimal examples
Section titled “Minimal examples”A single static page:
name: landing-pageservices: web: type: static path: /A Next.js app with a database:
name: my-appservices: web: type: nextjs path: /needs: database: trueSee Service types for node, python, and cron, and
Infrastructure needs for the full needs: vocabulary.
The full schema
Section titled “The full schema”Every supported field, commented. No real project uses all of these at once — this is a reference.
# ─── Identity ───────────────────────────────────────────────name: my-app # Required. Entity slug. 2-42 chars, lowercase a-z 0-9 and hyphens.description: Order API # Optional. One-line summary (max 280 chars).icon: "📦" # Optional. Single emoji or short text (max 64 chars).kind: app # Optional. 'app' (default) or 'agent'.
# ─── Networking ─────────────────────────────────────────────expose: true # Optional. Serve public HTTP (default true). false = internal-only.custom_domains: # Optional. Additional FQDNs the entity serves on. - orders.example.com
# ─── Health probe (entity-level override) ───────────────────probe: # Optional. path: /healthz # Probe path (default /). expected: "<500" # Expected status: '<500' (default), '200', '2xx'.
# ─── Deploy notifications ───────────────────────────────────notify: true # Optional. Notify on deploy failure (default true).
# ─── Scaling ────────────────────────────────────────────────scale: auto # Optional. 'auto' (default), 'alert', or an integer 1-10.
# ─── Infrastructure needs (canonical) ───────────────────────needs: # Optional. The deployer injects connection env vars from these. database: true # Mongo. Injects DATABASE_MONGODB_URL. cache: true # Redis (LRU eviction). Injects CACHE_REDIS_URL. kv: true # Redis (no eviction). Injects KV_REDIS_URL. queue: true # Redis for queues. Injects QUEUE_REDIS_URL. pubsub: true # Redis pub/sub. Injects PUBSUB_REDIS_URL. vector: pgvector # pgvector. Injects VECTOR_PGVECTOR_URL. object_storage: true # GCS bucket. Injects OBJECT_STORAGE_GCS_BUCKET / _REGION. disk: true # Persistent filesystem. Injects DISK_PATH (default /data). ai: true # AI Gateway access. Injects AI_GATEWAY_URL.
# ─── Inter-entity communication ─────────────────────────────calls: # Optional. Entities this app calls (outbound grants). - org:atomic/billing-apicallers: # Optional. Inbound caller policy. policy: auto # 'auto' or 'manual' (default 'manual'). scope: org # 'org', 'space', or 'explicit' (default 'org'). fallback: deny # 'deny' or 'warn' (default 'deny'). allowed_apps: # Required when scope is 'explicit'. - org:atomic/calling-app
# ─── Vault (external secret mapping) ────────────────────────vault: # Optional. Map ENV_VAR -> vault item key. STRIPE_KEY: stripe-live-key
# ─── Connectors and hooks ───────────────────────────────────connectors: - id: team-slack target: org # 'system' or 'org'. channel: "#deploys"hooks: # Outbound events. - on: deploy.failed # release.published | deploy.failed | feedback.received | entity.created via: team-slack # Must match a connector id. template: "Deploy failed for {entity_name}: {error}"triggers: # Inbound events routed into your app. - from: team-slack event: message channel: "#support" route: /webhooks/slack
# ─── Local development ──────────────────────────────────────dev: snapshot: mask: # Fields to redact in dev snapshots (collection.field). - users.email
# ─── Services ───────────────────────────────────────────────services: # Required. Map of service name to config. web: type: nextjs # 'node', 'nextjs', 'python', 'static', or 'cron'. path: / # HTTP route prefix. false = internal-only. port: 3000 # Container port (default 8080). env: # Static env vars (not secrets). LOG_LEVEL: info health: # Health probe config. path: /api/health expected: "200" depends_on: # Wait for these siblings before starting. - worker needs: # Per-service needs override (merged per key). queue: true
# ─── Agent block ────────────────────────────────────────────agent: # Optional. Present makes the entity an agent. purpose: Triage tickets schedule: "*/15 * * * *" memory: collection: triage_history retention: 90d budget: tokens_per_month: 100000 hard_stop: trueValidation rules
Section titled “Validation rules”- Name: 2–42 chars, lowercase letters, numbers, and hyphens, no leading or trailing hyphen.
- Reserved names cannot be used as an entity name — including
default,cloudgrid, and common Kubernetes system names. - Port: an integer 1–65535 (default 8080).
- Env var keys: uppercase letters, numbers, and underscores; must start with a letter or underscore.
- Connector IDs: 3–40 chars, lowercase letters, numbers, and hyphens.
Connectors and hooks
Section titled “Connectors and hooks”Connectors, hooks, and triggers let an entity talk to the outside world —
posting to Slack on a deploy, or routing an inbound message into your app.
They are declared in cloudgrid.yaml and wired to your org’s connectors. The
grid webhooks and grid wire
commands manage the same surface from the CLI.
A connector names an external destination and where it lives:
connectors: - id: team-slack # 3-40 chars, lowercase letters, numbers, hyphens. target: org # 'org' (org-scoped) or 'system' (platform-provided). channel: "#deploys" # Destination within the connector (e.g. a Slack channel).A hook sends an outbound event through a connector. The on: field is the
event; via: must match a connector id; template: is the message, with
{...} placeholders filled from the event payload:
hooks: - on: deploy.failed # release.published | deploy.failed | feedback.received | entity.created via: team-slack # Must match a connector id declared above. template: "Deploy failed for {entity_name}: {error}"A trigger routes an inbound event from a connector into one of your app’s HTTP paths:
triggers: - from: team-slack # A connector id. event: message # The inbound event to listen for. channel: "#support" # Optional filter within the connector. route: /webhooks/slack # The path in your app the event is POSTed to.Events fire whether they are declared here or subscribed with
grid webhooks — the YAML form keeps the wiring in the
manifest so it deploys with the entity.
The vault: block maps an environment variable your app reads to a secret
stored in your org’s vault. The secret value never appears in
cloudgrid.yaml — only the key that points at it — so the manifest stays safe
to commit.
vault: STRIPE_KEY: stripe-live-key # ENV_VAR: vault-item-key SENDGRID_KEY: sendgrid-prodAt deploy time the platform resolves each vault item and injects its value as
the named environment variable into every service. Your code reads
process.env.STRIPE_KEY and never sees the underlying store.
Use vault: for shared secrets managed at the org level. For one-off secrets
scoped to a single entity, set them with grid secrets
instead — both end up as environment variables at runtime.
needs: vs requires:
Section titled “needs: vs requires:”needs: is the canonical, current schema — the deployer injects connection
details from it. requires: is the deprecated v1 alias. Do not author new YAML
with requires:, and never set both needs: and requires: in the same file
(the validator rejects the combination). See
Infrastructure needs for the full mapping.
Agent block
Section titled “Agent block”An agent is an app with an agent: block — same entity, same deploy path.
name: daily-reportkind: agentservices: worker: type: cron schedule: "0 8 * * *"needs: database: true ai: trueagent: purpose: Generate and email daily sales reports schedule: "0 8 * * *"The block supports purpose (plain text), schedule (a cron expression),
memory (a collection and retention for persisting state across runs), and
budget (tokens_per_month and hard_stop).