---
title: "Self-hosting"
description: "Run Parsew on your own Cloudflare account: requirements, the one-command deploy, updates and removal."
---

Parsew is one Cloudflare Worker. Its source is available under the [PolyForm Shield License](https://polyformproject.org/licenses/shield/1.0.0): you may run it for yourself or your company, but not offer it as a competing service. A self-hosted deployment has no billing (every organization is unlimited), no landing page and no email unless you turn them on.

## Requirements

- Node.js 24 and pnpm (the repository pins pnpm through `packageManager`; run `corepack enable`).
- A Cloudflare account. The **Workers Paid** plan is recommended: password hashing at sign-in needs more CPU time than the Free plan allows.
- **R2** enabled on the account (the dashboard asks you to accept its terms once, even on the free tier).
- A **workers.dev subdomain** for the account. A brand-new account gets one the first time you open Workers & Pages in the dashboard; without it the Worker has no address (not needed with `PARSEW_DOMAIN`).
- An API token (see [permissions](/self-hosting/configuration#deploy-token-permissions)) and your account ID.

The Images binding's transformations are billed by Cloudflare Images (the first 5,000 unique transformations each month are free). Parsew caches every rendition, so each size and format of an image is transformed about once per data center per day.

## Deploy

```bash
git clone <your fork of the Parsew repository> parsew && cd parsew
pnpm install
export CLOUDFLARE_API_TOKEN=...
export CLOUDFLARE_ACCOUNT_ID=...
pnpm run deploy
```

`pnpm run deploy` builds the Worker, the dashboard and these docs, then Alchemy creates everything on your account and applies the database migrations: the D1 database, the R2 bucket, the Analytics Engine dataset and a read-only token for it, the Worker with its Images binding, and the hourly cron. It prints the Worker's URL.

(Use `pnpm run deploy`, not `pnpm deploy`: the latter is a built-in pnpm command.)

With no domain configured, everything is served from the Worker's `workers.dev` address:

| Path | What |
| --- | --- |
| `https://parsew.<subdomain>.workers.dev/` | The dashboard: sign up, create keys |
| `https://parsew.<subdomain>.workers.dev/i/{domain}` | The image API (`/i/og/{domain}` for Open Graph images) |
| `https://parsew.<subdomain>.workers.dev/docs` | These docs |

Point `@parsew/sdk` at it with `baseUrl: "https://parsew.<subdomain>.workers.dev/i"`.

Cloudflare doesn't run the edge cache on `workers.dev`, so every request there transforms the image again. For production use, serve Parsew from your own zone: set `PARSEW_DOMAIN` (see [Configuration](/self-hosting/configuration)) and deploy again. The image API then lives on `logo.<domain>` with the same paths as `logo.parsew.com`, and the dashboard on `app.<domain>`.

## Updates

Pull the new version and run `pnpm run deploy` again. New migrations are applied as part of the deploy.

## Stages and removal

Alchemy keeps its state in your Cloudflare account, so any machine with the token sees the same deployment. `pnpm run deploy` deploys the `prod` stage; `pnpm build && pnpm exec alchemy deploy --stage dev` deploys a separate `parsew-dev` Worker with its own database and bucket. `pnpm run destroy` removes the `prod` stage's resources, including the database and the R2 bucket of cached source images.
