Skip to content

Quick start

This page takes a fresh machine to a deployed PDS in around fifteen minutes, assuming the prerequisites are in place.

Run the scaffolder from an empty directory:

Terminal window
npm create pds@latest

This single command does the whole setup end to end:

  1. Prompts for a folder name, package manager, and whether to initialise a git repository.
  2. Copies the project template into the folder.
  3. Installs dependencies.
  4. Runs the setup wizard (pds init) inside the new project.

The setup wizard then collects the information needed to deploy:

  1. Cloudflare login. If wrangler is not authenticated, the wizard opens a browser to sign in.
  2. Account choice. New account or migration from an existing PDS.
  3. Handle and DID. The handle (for example alice.example.com) and the DID method. New accounts default to did:plc. Migrations carry the existing DID across.
  4. Hostname. The domain that will serve the PDS (for example pds.example.com).
  5. Account password. Used to sign in from the Bluesky app.
  6. Data placement. A Cloudflare location hint. See Data placement — this choice cannot be changed after the first deploy.

The wizard generates a signing key, a JWT secret, and a password hash. It writes the public values to wrangler.jsonc and the secrets to .dev.vars.

For a non-interactive scaffold (defaults for everything), use the --yes flag:

Terminal window
npm create pds@latest -- --yes --pm pnpm

See the create-pds CLI reference for every flag.

From the project directory:

Terminal window
pnpm run deploy

This runs wrangler deploy, which uploads the Worker, creates the Durable Object namespace, and provisions the R2 bucket. The first deploy takes a minute or two.

For a production deploy, push the secrets to Cloudflare:

Terminal window
pnpm pds init --production

The --production flag writes the secrets stored in .dev.vars to Cloudflare as Worker secrets instead of keeping them local.

Open https://pds.example.com/.well-known/atproto-did (replacing the hostname). The response is the account DID.

Open https://pds.example.com/xrpc/com.atproto.server.describeServer. The response is a JSON object describing the PDS’s capabilities.

For an interactive health check, run:

Terminal window
pnpm pds status

This checks connectivity, resolves the handle, verifies the repository is initialised, and reports the blob count.