Apps

The app catalogue, creating an app, starting and stopping it, and the subscription that follows its state.

An app is one deployable unit: a repository, an uploaded archive, a Docker image or a compose stack. Its settings have their own page, App settings; shipping it is on Deployments.

search(q) is not scoped to the active team

It answers with hits from every team the caller can reach, each carrying the team it lives in, so a client that has a name but not a team can find it and then work there (with X-Deplo-Team for a token, or the team argument of an MCP tool). A team the caller cannot enter right now contributes nothing. At most 50 hits per kind.

Reading

apps

Any signed-in principal. Returns [App!].

All apps in the active team, newest first.

ArgumentTypeDescription
qStringKeep only the apps whose name, slug or id contains this, ignoring case and separators. Use search to look across teams.
query {
  apps(q: "shop") {
    id
    slug
    name
    status
    latestDeployment { status createdAt }
  }
}

app

Any signed-in principal. Returns App.

One app by its team-scoped slug, or null.

ArgumentTypeDescription
slugString!
query {
  app(slug: "shop") {
    id
    name
    status
    productionUrl
    framework
    deployments { id status createdAt }
  }
}

Any signed-in principal. Returns SearchResults.

Find anything by name, slug or id across EVERY team the caller can reach - the one read in Deplo that is not scoped to the active team. Each hit says which team it is in. Separators and case are ignored, so "better auth" finds better-auth-docs. Hits from the active team come first, then the closest match. Teams the caller cannot enter right now (an unmet two-factor policy, a narrowed token) contribute nothing rather than failing the search.

ArgumentTypeDescription
kinds[SearchKind!]Which kinds to look through. Omitted means all ten - and each is a separate read PER TEAM, so name the ones you need.
qString!Part of a name, slug or id. Blank finds nothing.
query {
  search(q: "shop", kinds: [app, database]) {
    apps { id slug name team { slug } }
    databases { id name team { slug } }
  }
}

appRuntime

Any signed-in principal. Returns AppRuntime.

Live container state for an app, straight from the owning agent - the truth behind the stored status. Polled by the app's status badge.

ArgumentTypeDescription
appIdString!
query {
  appRuntime(appId: "prj_9f1c2ab7d3e4f5a6") {
    running
    total
    unhealthy
    unreachable
  }
}

overviewAppStates

Any signed-in principal. Returns [OverviewAppState!]!.

Batch runtime state for the visible Overview apps. Unknown or inaccessible IDs are omitted.

ArgumentTypeDescription
appIds[ID!]!
query {
  overviewAppStates(appIds: [["prj_9f1c2ab7d3e4f5a6"]]) {
    status
    appId
    neverDeployed
  }
}

appTransferInfo

Needs move_apps. Returns AppTransferInfo.

What transferring this app to another team would change, and which of the viewer's other teams could take it.

ArgumentTypeDescription
appIdString!
query {
  appTransferInfo(appId: "prj_9f1c2ab7d3e4f5a6") {
    appName
    targets {
      id
      name
      serverAvailable
    }
  }
}

Creating

createApp takes the whole first configuration in one input. The new-app wizard runs detectRepoFramework while you pick a repository and composeNameClashes before it submits a stack.

createApp

Needs create_apps. Returns App.

Create an app from a repository, an uploaded archive, a Docker image or a compose stack, with its first build settings, variables, domains and mounts. Deploys immediately unless the source needs an upload first.

ArgumentTypeDescription
inputCreateAppInput!
input.autoDeployBoolean
input.autoDomainString
input.autoDomainPathString
input.buildBuildConfigInput
input.buildServerIdStringWhere the app COMPILES, when that is not where it runs. Omitted is Automatic - a build-only server if the fleet has one.
input.composeString
input.composePortInt
input.composeServiceString
input.composeUpArgsStringExtra flags appended to docker compose up for a compose stack. Validated against the same allow-list the app's settings use.
input.deployBooleanWhether to start the first deployment. Defaults to true.
input.dockerImageString
input.env[AppEnvInput!]
input.environmentIdString
input.extraDomains[ExtraDomainInput!]
input.folderIdString
input.logoString
input.logoFromTemplateBooleanThe logo above is a template's own. Deplo reads it once for the plate that keeps a monochrome mark visible on both themes.
input.mounts[MountInput!]
input.nameString!
input.projectIdString
input.renameClashesBooleanRename a service whose name a neighbour on the destination network already answers to (db becomes db-2), carrying its references, instead of refusing the stack. See composeNameClashes.
input.repoGitRepoInput
input.serverIdString
input.sharedVarIds[String!]Shared variables to link to the new app, so its FIRST deploy already carries them (ADR-0012: linking is the injection, and it is opt-in).
input.sourceDeploySource!One of COMPOSE, DOCKER_IMAGE, GIT, GITHUB, UPLOAD.
mutation {
  createApp(
    input: {
      name: "shop"
      source: GITHUB
      repo: { provider: "github", repo: "acme/shop", branch: "main", url: "https://github.com/acme/shop", installationId: "ghi_9f1c2ab7d3e4f5a6" }
      build: { buildMethod: "nixpacks", port: 3000 }
      env: [{ key: "NODE_ENV", value: "production" }]
      autoDeploy: true
    }
  ) {
    id
    slug
    name
    status
    productionUrl
  }
}

createAppFromTemplate

Needs create_apps. Returns App.

Create an app from the public template catalog. deploy: true builds it right away.

ArgumentTypeDescription
inputCreateAppFromTemplateInput!
input.deployBooleanRequest the first deployment. Defaults to false; a token also needs deploy_apps.
input.environmentIdString
input.folderIdString
input.nameStringThe new App name. Omitted uses the template name.
input.projectIdString
input.serverIdString
input.templateSlugString!The catalog template slug from templateVariants.
input.variantSlugStringThe variant slug. Omitted uses the "default" variant.
mutation {
  createAppFromTemplate(
    input: { templateSlug: "umami", name: "analytics", deploy: true }
  ) {
    id
    slug
    name
    status
    productionUrl
  }
}

templateVariants

Any signed-in principal. Returns [TemplateVariantSummary!].

List the compact deployable variants in the public template catalog.

ArgumentTypeDescription
categoryStringFilter by the category slug.
qStringKeep variants whose template, variant, category or description matches.
query {
  templateVariants(q: "analytics") {
    templateSlug
    variantSlug
    name
    category
  }
}

refreshTemplates

Any signed-in principal. Returns Boolean.

Drop the cached template catalog so the next read hits the catalog service.

mutation {
  refreshTemplates
}

composeNameClashes

Needs create_apps. Returns [ComposeNameClash!].

The service names a stack would share with something already on the network it lands on - what createApp refuses it over, asked before creating so the caller can pass renameClashes instead. Empty when nothing clashes.

ArgumentTypeDescription
inputComposeNameClashesInput!
input.composeString!
input.environmentIdString
input.folderIdString
input.projectIdString
input.serverIdString
query {
  composeNameClashes(
    input: { compose: "services:\n  web:\n    image: nginx\n", serverId: "srv_9f1c2ab7d3e4f5a6" }
  ) {
    name
    owner
    renamedTo
  }
}

detectRepoFramework

Needs create_apps. Returns RecognizedFramework.

Read a GitHub repository before an app exists for it - the framework and the build command the new-app wizard prefills while you pick a repo. Null when there is nothing to read at all: a build method other than Nixpacks / Railpack (the only ones this applies to), a repository Deplo can't read, or one with neither a framework nor a script. Reads only; the app's first deploy re-derives and stores the framework.

ArgumentTypeDescription
branchStringBranch to read; empty => the repository's default branch.
buildMethodString!The build method the app will use, e.g. "nixpacks".
installationIdStringGitHub App installation to read a private repo through. Ignored unless it belongs to the active team.
repoString!The repository as "owner/name".
rootDirectoryStringBuild sub-directory, for a monorepo.
urlStringIts clone URL, when the caller has one (else derived).
query {
  detectRepoFramework(repo: "acme/shop", buildMethod: "nixpacks", installationId: "ghi_9f1c2ab7d3e4f5a6") {
    id
    name
    buildCommand
    startCommand
    defaultPort
  }
}

Running and stopping

startApp

Needs control_apps. Returns App.

Start a stopped app from its last deployment.

ArgumentTypeDescription
idString!
mutation {
  startApp(id: "prj_9f1c2ab7d3e4f5a6") {
    id
    slug
    name
    status
    productionUrl
  }
}

stopApp

Needs control_apps. Returns App.

Stop the app's containers without deleting anything.

ArgumentTypeDescription
idString!
mutation {
  stopApp(id: "prj_9f1c2ab7d3e4f5a6") {
    id
    slug
    name
    status
    productionUrl
  }
}

reloadApp

Needs control_apps. Returns String.

Re-apply the app's routing (domains + basic auth) to the running stack without a rebuild. Returns 'rerouted', 'unchanged', or 'deferred'.

ArgumentTypeDescription
idString!
mutation {
  reloadApp(id: "prj_9f1c2ab7d3e4f5a6")
}

rebuildApp

Needs deploy_apps. Returns App.

Rebuild the image from the current source and REPLACE the running container, even if nothing about the stack changed. Volumes, domains and data are untouched.

ArgumentTypeDescription
idString!
mutation {
  rebuildApp(id: "prj_9f1c2ab7d3e4f5a6") {
    id
    slug
    name
    status
    productionUrl
  }
}

bulkAppAction

Needs control_apps. Returns BulkAppActionResult.

Start, stop or restart EVERY app in one folder (its whole subtree) or one project (every environment). Gated again per app, so it only touches the ones the caller may control; one failure never stops the rest. Give exactly one of folderId / projectId.

ArgumentTypeDescription
actionBulkAppAction!One of restart, start, stop.
folderIdID
projectIdID
mutation {
  bulkAppAction(action: restart, folderId: "fld_9f1c2ab7d3e4f5a6") {
    ok
    failed
  }
}

bulkRedeployApps

Needs deploy_apps. Returns BulkAppActionResult.

Redeploy EVERY app in one folder (its whole subtree) or one project (every environment): the bulk twin of redeploy. Give exactly one of folderId / projectId.

ArgumentTypeDescription
folderIdID
projectIdID
mutation {
  bulkRedeployApps(projectId: "prc_9f1c2ab7d3e4f5a6") {
    ok
    failed
  }
}

Renaming, moving and deleting

renameApp

Needs configure_apps. Returns App.

Rename an app. The slug, and with it the auto domain, stays as it is.

ArgumentTypeDescription
idString!
nameString!
mutation {
  renameApp(id: "prj_9f1c2ab7d3e4f5a6", name: "shop") {
    id
    slug
    name
    status
    productionUrl
  }
}

reorderApps

Needs manage_team, or instance admin. Returns Boolean.

Set the team-wide display order of apps in Overview.

ArgumentTypeDescription
appIds[ID!]!
mutation {
  reorderApps(appIds: [["prj_9f1c2ab7d3e4f5a6"]])
}

transferAppToTeam

Needs move_apps. Returns Boolean.

Hand this app over to another team the viewer belongs to. A live app restarts briefly on that team's network (nothing is rebuilt); it leaves its folder/project, loses its shared-variable links, backup schedules and cron jobs, and keeps its GitHub connection only if the destination team has its own installation on that account. Returns true.

ArgumentTypeDescription
appIdString!
teamIdString!
mutation {
  transferAppToTeam(
    appId: "prj_9f1c2ab7d3e4f5a6"
    teamId: "team_9f1c2ab7d3e4f5a6"
  )
}

deleteApp

Needs delete_apps. Returns Boolean.

Delete the app. Returns as soon as the deletion is RECORDED - from that moment the app is refused by every gate and gone from the product, and the stack teardown finishes on the host behind the response. Its stored backups are deleted first; if one cannot be, nothing is deleted.

ArgumentTypeDescription
idString!
mutation {
  deleteApp(id: "prj_9f1c2ab7d3e4f5a6")
}

deleteApps

Needs delete_apps. Returns Int.

Bulk-delete several apps. Returns how many were recorded as deleted; the bounded-concurrency teardown runs behind the response.

ArgumentTypeDescription
ids[ID!]!
mutation {
  deleteApps(ids: ["ids"])
}

Logo and framework

Needs configure_apps. Returns App.

Set the app's logo (an image data-URI), or clear it with null.

ArgumentTypeDescription
idString!
logoString
mutation {
  updateAppLogo(id: "prj_9f1c2ab7d3e4f5a6", logo: "data:image/png;base64,…") {
    id
    logo
  }
}

Needs configure_apps. Returns App.

Auto-detect a favicon from the app's own files - its GitHub repo, its uploaded archive, or (for a compose stack) its files dir on its server, and set it as the logo. Errors if none is found.

ArgumentTypeDescription
idString!
mutation {
  detectAppLogo(id: "prj_9f1c2ab7d3e4f5a6") {
    id
    slug
    name
    status
    productionUrl
  }
}

setAppFramework

Needs configure_apps. Returns App.

Correct the framework Deplo recognised in this app's source (a catalog id such as "vite"), or pass null to go back to trusting detection. The correction survives every later deploy's re-detection.

ArgumentTypeDescription
frameworkString
idString!
mutation {
  setAppFramework(id: "prj_9f1c2ab7d3e4f5a6", framework: "vite") {
    id
    framework
  }
}

Subscription

appStatus

Any signed-in principal. Returns App.

Emits the app whenever its status (power / deployment) changes. Fires once immediately with the current snapshot, then on every change.

ArgumentTypeDescription
slugString!
subscription {
  appStatus(slug: "shop") {
    id
    status
    latestDeployment { id status }
  }
}

See also

Did this page help you?

On this page