Workspaces, sites, domains, and publishing

Last updated

Choose the right context, manage a site and its domains, configure routing, and publish production safely.

Select a workspace

Workspace commands
ploy workspace list
ploy workspace use --id <workspace-id>
ploy workspace use
ploy workspace current
ploy --workspace <workspace-id> workspace current

workspace list automatically pages through every accessible, non-frozen workspace. With --json, it prints { "workspaces": [...] }. workspace current prints the effective workspace and its source: flag, env, or stored.

Interactive selection requires a TTY. With --dry-run, workspace use requires an explicit --id.

ploy workspace create also creates a starter site named My Site. The CLI cannot delete that generated site. Remove it from the site dashboard if you do not need it.

Workspace resolution

  1. --workspace <id>
  2. PLOY_WORKSPACE_ID
  3. The workspace saved by ploy workspace use
  4. No workspace

Flags and environment variables do not change saved selection. Saving a different workspace clears the saved site.

Select an organization

If you belong to more than one organization, you can select one to limit workspace commands to it.

Organization selection
ploy organization list
ploy organization use --id <organization-id>
ploy organization use
ploy organization use --all

After you select an organization, workspace list and the workspace selector show only its workspaces, and workspace create adds new workspaces to it. A command that names a workspace in another organization fails. Run ploy organization use --all to work with every organization again.

Selecting a different organization clears the saved workspace and site. Interactive selection requires a TTY. With --dry-run, organization use requires --id or --all. organization use is unavailable when PLOY_API_TOKEN is set, and API tokens ignore a saved organization.

Select a site

Site selection
ploy site list
ploy site use --id <site-id>
ploy site use

site list returns up to 100 sites in the effective workspace. With --json, it prints { "sites": [...] }. site use saves a site but does not change the effective workspace; the site must belong to the saved current workspace.

Interactive selection requires a TTY. With --dry-run, site use requires --id.


ploy site init

Create a blank site, start from a compatible local repository, or provide an initial request for a new blank site.

Version compatibility. ploy site init does not import a website from a URL. If ploy site init --help on your machine still lists a --slurp option, run ploy update. To bring over a public website, import it in the Ploy app, then select the resulting site in the CLI.

Create a site
ploy site init [--name <title>] [--from <path>] [--prompt <message> | --prompt-file <path>] [--wait] [--json]
OptionPurpose
--name <title>Optionally name the new site.
--from <path>Create a site from a compatible local Ploy Astro repository, rather than a blank site.
--prompt <message>Start a Ploy with an initial request on the new blank site.
--prompt-file <path>Read the initial request from a UTF-8 file instead of an inline message.
--waitWait for provisioning, or follow the prompted Ploy until its turn completes.
--jsonPrint machine-readable output.

Use --from for a local repository, or a prompt option for a new blank site. These are different starting paths, not direct URL-import options. You must be authenticated and have access to the workspace.

Site creation examples
ploy site init --name "My site"
ploy site init --from ./my-astro-site --wait
ploy site init --prompt "Build a product landing page" --wait
ploy site init --prompt-file brief.md --wait --json

A prompt starts work and uses AI credits. Review Bring your own repo for local repository compatibility requirements. Use ploy site init --help to check the syntax in your installed version.

Bring over an existing website in the app

  1. Confirm that the source pages are publicly reachable over HTTP(S) without signing in.
  2. Open Ploy, provide the public URL, and ask Ploy to import or reconstruct the website.
  3. Review the resulting pages and behavior, including content, links, images, and interactions. Correct anything missing or inaccurate.
  4. Publish only after checking the result.

Do not expect an identical import of private pages or dynamic features. See Site Builder for review guidance.

To use the CLI with that site afterward, authenticate, select the workspace that contains it, list its sites, and select the existing site's ID:

Select the site created in the app
ploy workspace list
ploy workspace use --id <workspace-id>
ploy site list
ploy site use --id <site-id>
ploy site status

Use the IDs from the workspace and site lists, then check the selected site's status. ploy site use selects an existing site; it does not create or import one. Do not run site init again to connect to it.

ploy site status

Read site readiness
ploy site status [--id <site-id>] [--json]

--id temporarily overrides the selected site without changing selection. Site state is pending, ready, failed, or status-unavailable.

Inspect the retained site with ploy site status --id <site-id> before retrying creation if its outcome is uncertain.

Look up identified visitors

Use ploy site visitors to read one page of identified people and companies for the selected site. See the visitor lookup reference for prerequisites, filters, pagination, and JSON output.


ploy site publish

Publish production
ploy site publish [--wait] [--json]

The command always targets production. There is no target flag, staging mode, or unpublish command. A selected workspace and site are required.

Retries safely rejoin the same operation or an already-active publish for the site.

Accepted publish
{
  "operationId": "<operation-id>",
  "reused": false,
  "workflowStarted": true
}

A reused response also includes reuseReason: "operation_key" or "active_site".

Wait for production

With --wait, the CLI polls for up to nine minutes and exits 0 only when production reaches ready. If the CLI reaches its request limit while it polls, it slows down and keeps waiting until the nine minutes are up. The publish or site initialization continues in the background either way. Wait about one minute, then re-check with ploy site publish-status <operation-id> or ploy site status --id <site-id>.

  • 1: production reached a terminal failure.
  • 5: polling timed out; the publish is still running.
  • 6: API contact was lost; the publish is still running.

With --json, every outcome prints exactly one JSON object on stdout containing operationId.

Preview a publish

Dry-run production publish
ploy --dry-run site publish
Dry-run response
{
  "dryRun": true,
  "target": "production",
  "workspaceId": "<workspace-id>",
  "siteId": "<site-id>"
}

ploy site publish-status

Read a publish operation
ploy site publish-status <operation-id> [--json]

The operation must belong to the selected workspace and site pair. Exit 0 means the read succeeded; inspect status and deployment rows to determine the publish outcome. --dry-run is not supported.

Publish operation
{
  "operationId": "<operation-id>",
  "status": "in_progress",
  "deployments": [
    {
      "target": "production",
      "status": "building",
      "currentStep": "Building site",
      "url": null,
      "error": null
    }
  ]
}

Operation status is in_progress, succeeded, or failed. Deployment status is queued, building, ready, error, or cancelled.

The build log returned by publish-status is currently truncated to about 1 KB. Open the site in the Ploy dashboard, then go to Deploys, open the failed deployment, and view its full build log there.


Custom domains

ploy domain list [--json]

Lists every custom domain configured for the selected site.

List custom domains
ploy domain list
ploy domain list --json

--json prints { "domains": [...] } instead of human-readable hostname and state lines. Each domain object includes:

  • id and hostname
  • state and sslStatus
  • dnsVerified and kvSynced
  • lastError

ploy domain add <hostname> [--json]

Starts custom-domain setup or continues setup after the required DNS records have propagated.

Connect a custom domain
ploy domain add www.example.com
# Add the returned DNS records and wait for propagation, then run it again:
ploy domain add www.example.com --json

This command is intentionally repeatable. The first invocation may return required DNS records. After propagation, run the same command again to connect the domain.

The DNS plan can include the requested hostname and an apex or www companion. Possible phases are:

PhaseMeaning
dns_pendingDNS records still need to be added or propagated.
provisioningDNS is ready and domain provisioning has started.
connectedThe domain is connected.

The JSON result includes the primary hostname and either the required DNS records or the affected domain objects.

Adding a custom domain requires workspace admin or owner access and the workspace's custom-domain capability.

ploy domain status <hostname> [--json]

Shows the provisioning and connection status of one hostname on the selected site.

Inspect a domain
ploy domain status www.example.com --json

Without --json, the command prints the hostname and state, followed by the most recent error when one exists. JSON output contains the complete domain object.

ploy domain remove <hostname> [--json]

Removes a draft or non-live custom domain from the selected site.

Remove a non-live domain
ploy domain remove www.example.com --json

--json prints { "removed": true, "hostname": "..." }. The command removes only the named hostname.

The CLI refuses to remove a hostname currently serving live traffic because that operation requires fresh step-up authentication. Removing a domain requires workspace admin or owner access.


Routing rules

Routing rules belong to the selected site's effective custom domain.

ploy site routing get [--hostname <hostname>] [--json]

Prints the selected site's complete editable routing-rules document.

Read routing rules
ploy site routing get
ploy site routing get --hostname www.example.com
OptionMeaning
--hostname <hostname>Selects a connected hostname when the site does not yet have an unambiguous default hostname.
--jsonUses structured JSON errors. Successful output is already the routing document as formatted JSON.
Routing document
{
  "rules": [],
  "defaultFallback": {}
}

defaultFallback is optional. The printed document can be edited and passed directly to ploy site routing set.

How hostname selection works

  1. If the site has an elected default custom domain, that domain is used.
  2. If no default exists and exactly one hostname is connected, that hostname is unambiguous.
  3. If no default exists and several hostnames are connected, use --hostname.
  4. Once a default exists, an explicit --hostname must name that default. Other hostnames redirect to it and do not own independent routing rules.

ploy site routing set --file <path> [options]

Replaces the selected site's entire routing-rules document.

Replace routing rules
ploy site routing get > routing.json
# Edit routing.json, then validate the complete replacement:
ploy site routing set --file routing.json --dry-run
# Apply it:
ploy site routing set --file routing.json --json
# Standard input is also supported:
cat routing.json | ploy site routing set --file -
OptionMeaning
--file <path>Required JSON document. Use - to read from standard input.
--hostname <hostname>Selects a connected hostname when the site has no unambiguous default.
--dry-runValidates the complete replacement and reports the rule-count change without changing the database or hosting configuration. It currently requires a connected custom domain.
--jsonPrints structured success, preview, and error output.

The file must be a JSON object containing a rules array:

Routing replacement file
{
  "rules": [
    {
      "match": {},
      "action": {}
    }
  ],
  "defaultFallback": {}
}

A redirect rule uses this action shape:

Redirect routing rule
{
  "pathPrefix": "/old-path",
  "action": {
    "type": "redirect",
    "destination": "/new-path",
    "statusCode": 301
  }
}

This is a complete replacement, not a patch. Read the current document, modify it, and pass the full result back to routing set. The shared routing schema allows a maximum of 20 total rules. A dry run currently works only after a custom domain is connected.

Dry-run checks and output

A dry run performs the same server-side checks as a real write:

  • Document validation and admin authorization
  • Hostname selection and hosting configuration ownership
  • Publication eligibility
  • Enhanced-security step-up requirements

Without --json, the CLI prints the current and proposed rule counts:

Human-readable dry run
Would replace routing on www.example.com (rule count: 1 → 2).

With --json, it prints:

JSON dry run
{
  "dryRun": true,
  "hostname": "www.example.com",
  "currentRuleCount": 1,
  "nextRuleCount": 2
}

Recover from an edge sync failure

After a real write, the server synchronizes the routing document with Ploy's hosting infrastructure. If synchronization fails after the database update:

  • The command exits with code 1.
  • The CLI tells you to retry the same complete routing set command.
  • With --json, it prints the structured response, including kvSyncError, before failing.
  • Repeating the same command is safe and is the supported recovery path.

Code Sync

Code Sync is included with every paid plan. Its commands use the site selected by ploy site use and require that site to belong to the effective workspace. They are human-readable only: no --json or --dry-run.

ploy site code-sync init

Initialize Code Sync
ploy site code-sync init

Connect GitHub to Ploy through the OAuth step in the dashboard first. Then Ploy prepares the selected site's repository, creating it when needed, and prints connection status, setup links, and HTTPS and SSH clone commands.

The first sync immediately after connecting GitHub can return Internal server error. Retry ploy site code-sync sync once.

Code Sync workflow
git clone https://github.com/<owner>/<repo>.git
cd <repo>
# make changes on main
git pull --rebase origin main
git push origin main
ploy site code-sync sync

ploy site code-sync sync

Import GitHub main into Ploy
ploy site code-sync sync

On success, the CLI prints the imported GitHub commit and resulting Ploy site-workspace commit. If changes conflict, resolve them in the editor and retry.


Keep going