Browse docs All docs
Docs / Subprocessors & data flow
Docdeploymill://docs/subprocessors

Subprocessors & data flow

A subprocessor is a third-party service DeployMill sends data to in order to do its job, host your app, store your database, keep your source, send an invite email, and so on. This page names every subprocessor in DeployMill's default managed stack, what data each one receives, and why.

It exists so you (and your auditors) can see exactly where customer data goes. If you're assembling a vendor-management list for SOC 2, or a subprocessor appendix for a DPA / GDPR Article 28 agreement, this is the source of truth for the default deployment.

Two honesty caveats up front:

  • This reflects the default managed stack. DeployMill's primitives (compute, database, domain, secrets, source, object storage) are provider-neutral interfaces with swappable backends. The vendors below are today's backends, not a permanent contract. If a backend is swapped (a different compute target, a different object store), this list changes, and this page will change with it.
  • It's deployment-dependent. Several subprocessors are only engaged if the operator running DeployMill has configured them. An operator can run with email, SSO, or object storage left unconfigured, in which case that subprocessor receives nothing at all. Each row notes when this applies.

The data-flow inventory

SubprocessorData categories receivedPurposeNotes / region
Compute host (operator-run infrastructure)App build context (source pulled for the build); the app's full environment-variable blob, including secret values and DATABASE_URL written in plaintext (the container needs them at runtime)Builds, runs, and health-gates your deployed apps and previewsThe compute primitive runs on infrastructure the operator controls, not a third-party compute SaaS. Secrets are encrypted at rest in DeployMill's own store, but binding a secret into an app writes the plaintext into the container's runtime environment. Encryption at rest protects the source of truth and keeps values out of agent transcripts, not from the host that runs your container. Region/hosting is operator-determined.
Neon (managed Postgres, optional database backend)Whatever your deployed app writes to its database, i.e. your application's own dataManaged Postgres database + connection stringOne Neon project per organization (deploymill-<orgSlug>), one database per app; previews get a copy-on-write branch. Only engaged when a project declares database: { "engine": "postgres", "provider": "neon" }, and only if the operator configured a Neon API key. The default database backend is not a subprocessor at all. It's internal Postgres on operator-run infrastructure (a file-backed SQLite option is implemented behind the same seam but currently disabled as a selectable backend), so by default no third party receives your database content.
Supabase (managed Postgres, optional database backend)Whatever your deployed app writes to its database, i.e. your application's own dataManaged Postgres database + connection stringOne Supabase project per organization, one database + role per app; previews share the parent's database (no per-preview branch). Only engaged when a project declares database: { "engine": "postgres", "provider": "supabase" }, and only if the operator configured Supabase credentials.
Xata (managed Postgres, optional database backend)Whatever your deployed app writes to its database, i.e. your application's own dataManaged Postgres database + connection stringBring-your-own-account: one Xata project per organization, one database + role per app on the project's main branch; previews get a copy-on-write branch (like Neon). Implemented behind the database seam but currently disabled as a selectable backend. When enabled it is engaged only when a project declares database: { "engine": "postgres", "provider": "xata" }, and only if the operator configured Xata credentials (API key, organization id, region).
GitHub (source backend)Repository source code and file contents (commits made via push_files, repos created by start_project)Source / version control, where your project's code and .deploymill/project.json liveThe source primitive. DeployMill authenticates as a GitHub App installation (or a shared token). Region/hosting is GitHub's.
Cloudflare R2 (object storage)Objects/blobs your app uploads (media, user uploads, datasets)S3-compatible object storageOne bucket per app with bucket-scoped credentials minted per app. Only engaged when a project declares object storage, and only if the operator configured Cloudflare R2 credentials.
Resend or Amazon SES (transactional email)Recipient email address + the invite / transactional email contentSending organization invites and transactional emailEmail is not a core primitive but follows the same swappable-backend posture, two backends are wired behind EMAIL_PROVIDER (Resend and Amazon SES). Whichever the operator selects is the engaged subprocessor. Processes PII (email addresses). Only engaged if the operator configured email, otherwise no invite emails are sent and nothing reaches either provider.
Google / GitHub (OAuth sign-in)The OAuth sign-in handshake for "Continue with Google" / "Continue with GitHub", the identity assertion for the signing-in user (e.g. email, name)Identity provider for optional social sign-inIdentity only, the provider receives no application data, no source, no secrets, no database content. Each is only engaged if the operator configured that provider's OAuth client credentials, and only for users who choose that social sign-in. (GitHub also appears above as the source backend. The sign-in handshake is a separate, identity-only flow.)
Stripe (payment/billing processor)The organization's billing contact email + name, org identifiers (orgId/orgSlug/sku), and subscription/payment data (plan, status, and the card/payment details the customer enters directly into Stripe-hosted Checkout)Self-serve subscription billing, Checkout + Billing-Portal sessions and plan/subscription stateBilling PII only, Stripe receives no application data, no source, no secrets, no database content. A Stripe Customer is created per billing org with the billing email/name + org metadata. Only engaged if the operator configured Stripe (STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET + at least one STRIPE_PRICE_*); self-serve billing is off and the routes 503 until then. Region/hosting is Stripe's. See Stripe's DPA.
Observability backend (Grafana Cloud, or any OTLP endpoint the operator points at)The control plane's own operational telemetry, traces, metrics, and (by default, when telemetry is on) the server's console.* log lines, which can include identifiers like app names and org slugs. Not your app's runtime logs, secrets, source, or database contentPlatform monitoring/alerting for the DeployMill control planeOnly engaged if the operator enabled telemetry (OTEL_ENABLED=true with an OTLP endpoint or Grafana Cloud credentials). Off by default. When unconfigured, nothing is shipped.

What DeployMill itself holds

Separate from the subprocessors above, DeployMill stores in its own Postgres database: your account and organization records, org-scoped secrets (encrypted at rest with AES-256-GCM), app/preview metadata, and the audit trail. Secret values are never returned to MCP clients and never echoed into an agent transcript. They enter only through a single-use browser hand-off and leave only when injected server-side into an app's environment (which is what hands them to the compute backend, above).

Keeping this honest

Because the primitives are provider-neutral, the interfaces are stable but the vendors can change. When a backend is added or swapped (or when an operator turns a previously-unconfigured subprocessor on) this page is the document that must be updated to stay accurate. Treat it as a maintained list, not a one-time snapshot.