---
title: Add custom domains to your app
description: Connect a DNS provider, review the exact records your product needs, apply only what the customer approved, and keep credentials and policy in your app.
sidebar:
  label: Overview
seo:
  title: Add custom domains to your app
---

DomainKit helps you add custom domains to a SaaS product without sending customers to copy-paste
DNS instructions. It turns your product's DNS requirements into a plan a customer can review,
applies only the plan digest they approved, keeps a receipt of every write, and plans cleanup from
that receipt. Cloudflare and Vercel are built in, and a provider is one declarative value.

Your app keeps identity, tenancy, credentials, storage, routes, consent, and audit. DomainKit
supplies the lifecycle, not a hosted control plane.

```package-install
domainkit effect
```

<Snippet file="examples/core/lifecycle.ts" region="program" title="Plan, approve, apply, observe" />

**[Quickstart](/docs/quickstart)**

Build, approve, and apply a plan in memory, without credentials.

**[Plans](/docs/core/plans)**

How review, approval, apply, and receipts fit together.

**[Connections](/docs/core/connections)**

Connect a provider without putting credentials in the browser.

**[Host integration](/docs/guides/host-integration)**

Mount the routes, write `Identity`, install storage.

**[React](/docs/react)**

A complete flow, or the controllers behind it.

**[Glossary](/docs/glossary)**

The shared vocabulary for the lifecycle, connections, observation, and host seams.

**[Custom domain setup](/guides/custom-domain-onboarding)**

A step-by-step guide from declared records to verified DNS.

**[Email sending domains](/guides/email-domain-setup)**

SPF, DKIM, MX, and tracking records for your customers' domains.

**[Custom domains on Vercel](/guides/vercel-custom-domains)**

Add the hostname with Vercel, then write the customer's DNS records.

**[Samva case study](/customers/samva)**

How an email API sets up customer domains with DomainKit.

<ProviderCard title="Cloudflare" href="/https/domain-kit.dev/docs/providers/cloudflare" provider="cloudflare">
  API tokens, or OAuth with refresh and revoke.
</ProviderCard>

<ProviderCard title="Vercel" href="/https/domain-kit.dev/docs/providers/vercel" provider="vercel">
  Personal and team tokens, or a marketplace integration.
</ProviderCard>

## Compare

- [DomainKit vs Entri](/compare/entri)
- [Cloudflare for SaaS and DomainKit](/compare/cloudflare-for-saas)
- [Domain Connect and DomainKit](/compare/domain-connect)
- [Copy-paste DNS instructions and where they break](/compare/manual-dns)

## The safety model

- **Nothing is written before it is shown.** A plan lists the creates, the exact matches, and the
  conflicts, with a digest over all of them.
- **Apply accepts one approval.** The approval names the digest and the exact operations; apply
  re-plans first and fails `Stale` if the zone moved.
- **Additive, fail closed.** Missing records are created, exact records are no-ops, and
  incompatible state is a conflict. DomainKit never updates or deletes a record it did not create.
- **Partial application is data.** A failure after a confirmed write produces a receipt with
  `status: "partial"` listing every operation, not an exception.
- **Cleanup is its own plan.** It is built from an apply receipt, and a record that no longer
  matches is left alone.

## Who owns what

| DomainKit                                      | Your application                             |
| ---------------------------------------------- | -------------------------------------------- |
| Building the plan and its digest               | Which DNS records the product needs          |
| Refusing an apply the customer did not approve | Identity, tenancy, consent, and audit policy |
| Cloudflare and Vercel integrations             | The database and the encryption key          |
| Provider readback and public DNS observation   | Authenticated routes and product readiness   |
| Cleanup bound to an apply receipt              | When a customer may remove records           |
| React flows and their contracts                | Branding, layout, wording, and telemetry     |

## Entry points

| Package                | Use it for                                                  |
| ---------------------- | ----------------------------------------------------------- |
| `domainkit`            | Lifecycle services, host seams, providers, values, failures |
| `domainkit/server`     | The mountable route group and its Web handler               |
| `domainkit/client`     | The browser transport over those routes                     |
| `domainkit/testing`    | Fakes, a recording transport, and conformance runners       |
| `@domainkit/react`     | Headless React hooks for the flow, over your transport      |
| `@domainkit/capsuledb` | Optional PostgreSQL persistence for Effect hosts            |
