Skip to main content

Project Descriptor

A project descriptor is the compiled representation of your foundry.config.ts. The create-foundry-app CLI compiles your TypeScript config into this JSON shape and submits it to POST /projects/deploy. You can also construct and submit the descriptor directly via the API.

Top-level fields

FieldTypeRequiredDescription
namestringyesStable project identity. Changing the name creates a new project rather than updating the existing one.
resourcesarrayyesEvery declared resource. Exactly one must have kind: app.
dependenciesobjectnoMaps a resource logical_name to a list of logical_name values that must be Running before it is created.
organization_idUUIDnoScopes the project to an organization you belong to. Omit for a personal project.

Resources

Each entry in the resources array has three fields:

FieldTypeRequiredDescription
logical_namestringyesUnique name for this resource within the project. Used as the key in dependencies and as $name references inside other resources' specs.
kindstringyesOne of postgres, files, auth, app.
specobjectyesKind-specific configuration. Unknown keys are rejected.

Dependency ordering

The dependencies map expresses which resources must reach Running before a given resource is created. Independent resources provision concurrently.

{
"dependencies": {
"auth": ["db"],
"web": ["db", "auth"]
}
}

The engine also discovers implicit ordering edges from $logical_name references inside spec values: if the web spec contains "$db.service_id", the engine treats db as a dependency of web even if you did not list it explicitly.

postgres spec

Provisions a managed PostgreSQL service.

FieldTypeDefaultDescription
planstringtier-1Compute plan name (e.g. tier-1, tier-2).
storage_gbinteger25Data disk size in GB.
storage_tierstringplatform defaultStorage tier: standard or maxiops.
versionstringplatform defaultPostgreSQL major version (e.g. "17").
extensionsstring arraynoneExtensions to install (e.g. ["pgvector", "postgis"]).
default_databasestringdefaultdbName of the default database created during provisioning.

files spec

Provisions an S3-compatible object storage bucket.

FieldTypeDefaultDescription
quota_gbintegernoneSoft quota in GB (notification threshold).
quota_hard_gbintegernoneHard quota in GB (enforced ceiling).

auth spec

Attaches end-user authentication to the app resource. Auth does not create a standalone service; it enables an auth_configuration on the app it depends on. The auth resource must declare a dependency on the app resource (or the engine infers it from $ref notation).

FieldTypeDefaultDescription
providersstring array["password"]Enabled auth providers. Supported: password, google, github.
smtpobjectnoneSMTP configuration for magic-link email delivery. If absent, email-based flows are disabled.
idp_providersarraynoneSocial login provider configurations (client ID, secret).

When auth is enabled the reconciler records an issuer_url in the resource's outputs once the auth configuration is active.

app spec

Provisions a hosted application container.

FieldTypeRequiredDescription
imagestringyesContainer image reference (e.g. ghcr.io/myorg/myapp:latest).
portintegeryesThe container port the application listens on.
envobjectnoAdditional environment variables to inject alongside the platform-managed ones.
planstringnoCompute plan. Defaults to tier-1.
storage_gbintegernoPersistent storage for the app container.
custom_domainsstring arraynoCustom domains to attach to the app.

Complete example

The following descriptor declares a to-do application backed by PostgreSQL with the pgvector extension, end-user auth with password and Google login, and an application container.

{
"descriptor": {
"name": "my-todo-app",
"resources": [
{
"logical_name": "db",
"kind": "postgres",
"spec": {
"plan": "tier-2",
"storage_gb": 50,
"storage_tier": "maxiops",
"version": "17",
"extensions": ["pgvector"]
}
},
{
"logical_name": "uploads",
"kind": "files",
"spec": {
"quota_gb": 100
}
},
{
"logical_name": "auth",
"kind": "auth",
"spec": {
"providers": ["password", "google"],
"smtp": {
"host": "smtp.example.com",
"port": 587,
"username": "noreply@example.com",
"password": "smtp-secret"
},
"idp_providers": [
{
"provider": "google",
"client_id": "your-google-client-id",
"client_secret": "your-google-client-secret"
}
]
}
},
{
"logical_name": "web",
"kind": "app",
"spec": {
"image": "ghcr.io/myorg/todo:latest",
"port": 3000,
"plan": "tier-2",
"env": {
"NODE_ENV": "production",
"LOG_LEVEL": "info"
}
}
}
],
"dependencies": {
"auth": ["db"],
"web": ["db", "uploads", "auth"]
}
}
}

When this project reaches Running, the web container will have the following environment variables injected by the platform, in addition to those declared in env:

VariableSource
DATABASE_URLPostgreSQL connection string for db
S3_ENDPOINTFiles endpoint for uploads
S3_BUCKETBucket name for uploads
S3_ACCESS_KEYAccess key ID for uploads
S3_SECRETSecret access key for uploads
FOUNDRY_API_TOKENScoped platform token (read-only: services, files)
FOUNDRY_API_URLBase URL of the FoundryDB API

Resource naming

The engine derives stable service names from the project name and the resource's logical_name. The same project-plus-logical-name always yields the same service name, which keeps re-deploys pointing at the same underlying service. Names are lowercased, sanitized to [a-z0-9-], and capped at 60 characters.

Next steps