Relevant source files
The following files were used as context for generating this wiki page:
- apps/web/app/api/domains/[domain]/route.ts
- apps/web/app/api/domains/route.ts
- apps/web/app/api/domains/[domain]/verify/route.ts
- apps/web/lib/dynadot/register-domain.ts
- apps/web/app/api/domains/[domain]/domain-connect/apply/route.ts
- apps/web/ui/domains/domain-card.tsx
- apps/web/app/api/domains/[domain]/forward-instructions/route.ts
- apps/web/app/(ee)/api/email-domains/[domain]/verify/route.ts
- apps/web/app/(ee)/admin.dub.co/(dashboard)/domains/page.tsx
- apps/web/lib/api/domains/claim-dot-link-domain.ts
- apps/web/app/[domain]/page.tsx
- apps/web/app/(ee)/api/domains/register/route.ts
- apps/web/app/api/domains/[domain]/validate/route.ts
- apps/web/app/(ee)/api/admin/domains/register-premium/route.ts
- apps/web/lib/api/domains/finalize-premium-domain-registration.ts
- apps/web/lib/api/domains/get-domain-response.ts
- apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/domains/page-client.tsx
- apps/web/lib/domain-connect/constants.ts
- apps/web/lib/api/domains/verify-domain.ts
- apps/web/app/(ee)/api/email-domains/route.ts
- apps/web/app/(ee)/api/cron/domains/verify/route.ts
- apps/web/scripts/customers/annature/import-domains.ts
- apps/web/app/(ee)/api/admin/domains/renew/route.ts
- apps/web/ui/domains/domain-configuration.tsx
- apps/web/lib/dynadot/client.ts
- apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/domain/custom/page.tsx
- apps/web/ui/partners/program-link-configuration.tsx
- packages/utils/src/functions/domains.ts
- apps/web/lib/api/domains/get-domain-search-availability.ts
- apps/web/lib/api/domains/initiate-premium-domain-registration.ts
Overview
Domain Management serves as the foundational infrastructure layer in Dub for connecting, registering, provisioning, and verifying custom link domains. This subsystem bridges the gap between workspace project management, edge routing providers like Vercel, automated DNS configuration standards via Domain Connect, and external domain registrars like Dynadot. By abstracting the complexities of DNS validation, SSL certificate provisioning, and domain lifecycle maintenance, Dub enables marketing teams and link attribution platforms to operate entirely under their own branded domains.
Sources: apps/web/app/api/domains/route.ts:96-233
The architecture addresses several core engineering challenges: tracking domain verification states across distributed edge networks, handling automated DNS setup with strict origin and signature security validations, and managing automated or premium domain registration invoices integrated with Stripe billing and Dynadot registrar APIs. Interfacing tightly with route handlers, background cron jobs, and database models, Domain Management ensures that every incoming custom URL resolves accurately while maintaining strict multi-tenant boundaries and plan-based limits.
Sources: apps/web/app/api/domains/domain/verify/route.ts:16-139
Sources: apps/web/app/api/domains/route.ts:96-233, apps/web/app/api/domains/domain/verify/route.ts:16-139
Domain Validation and Registration Pipeline
When a workspace attempts to add or claim a custom domain, the request passes through rigorous validation layers to check syntax, prevent reserved subdomain collisions, and detect existing active sites or domain conflicts.
Sources: apps/web/app/api/domains/route.ts:96-233
The validation sequence begins by checking string validity through regular expressions, filtering out forbidden structures such as domains starting with www. or conflicting with reserved .dub.link subdomains. For standard custom domains, the system performs both an active HTTP HEAD check (with a 3-second timeout) and a DNS lookup (dns.resolve) to verify whether a site is already actively configured. If a site responds or records exist, the API returns a status flag indicating potential conflicts.
Sources: apps/web/app/api/domains/domain/validate/route.ts:8-48
Sources: apps/web/app/api/domains/route.ts:96-233, apps/web/app/api/domains/domain/validate/route.ts:8-48
For workspaces claiming free or premium .link domains, the registration flow interacts directly with Dynadot via the registerDomain client, records expiration timestamps, provisions a default root link (_root), and queues Vercel domain and nameserver configuration tasks.
Sources: apps/web/lib/api/domains/claim-dot-link-domain.ts:15-163, apps/web/lib/dynadot/register-domain.ts:24-64
DNS Verification and Vercel Integration
Domain verification relies on querying Vercel's domain and configuration APIs to evaluate whether records point correctly to Dub's target endpoints (76.76.21.21 for A records, cname.dub.co for CNAME records).
Sources: apps/web/lib/domain-connect/constants.ts:1-7
The verification endpoint (GET /api/domains/[domain]/verify) evaluates verification status by executing parallel requests to getDomainResponse(domain) and getConfigResponse(domain). If Vercel reports the domain as unverified, the system invokes verifyDomainWithRetry(domain), which executes up to 3 retry attempts separated by a configurable delay (2500ms).
Sources: apps/web/app/api/domains/domain/verify/route.ts:16-139, apps/web/lib/api/domains/verify-domain.ts:16-41
Note
During domain verification, if Vercel configuration responses indicate conflicting records or misconfigurations, the system updates the Prisma domain record to verified: false and sets lastChecked to the current timestamp.
Sources: apps/web/app/api/domains/domain/verify/route.ts:70-85
export const verifyDomainWithRetry = async (
domain: string,
{
attempts = 3,
delayMs = 2500,
}: { attempts?: number; delayMs?: number } = {},
) => {
let last: any = null;
for (let i = 0; i < attempts; i++) {
if (i > 0) {
await sleep(delayMs);
}
try {
last = await verifyDomain(domain);
} catch (error) {
if (i === attempts - 1) {
throw error;
}
continue;
}
if (last?.verified) {
return last;
}
}
return last;
};Sources: apps/web/lib/api/domains/verify-domain.ts:16-41
Domain Connect Automated DNS Setup
To simplify DNS configuration for end-users, Dub implements Domain Connect support, allowing automated configuration via supported DNS providers such as Cloudflare and Vercel.
Sources: apps/web/app/api/domains/domain/domain-connect/apply/route.ts:24-143
When a user triggers auto-configuration via POST /api/domains/[domain]/domain-connect/apply, the system discovers the apex domain's Domain Connect service descriptor via discoverDomainConnect(apex). It validates that the provider URL satisfies allowed synchronization origins (isAllowedSyncUXOrigin) and constructs a cryptographically signed apply URL using RSA private keys (DOMAIN_CONNECT_PRIVATE_KEY).
Sources: apps/web/app/api/domains/domain/domain-connect/apply/route.ts:24-143
| Constant / Parameter | Value / Description |
|---|---|
DUB_CUSTOM_DOMAIN_A_RECORD | 76.76.21.21 (Target IP for apex domains) |
DUB_CUSTOM_DOMAIN_CNAME | cname.dub.co (Target host for subdomains) |
DOMAIN_CONNECT_KEY_HOST | _dck1 (TXT record key host for Domain Connect) |
DEFAULT_DC_SERVICE_APEX | links-apex (Service ID for apex configuration) |
DEFAULT_DC_SERVICE_SUBDOMAIN | links-subdomain (Service ID for subdomain configuration) |
Sources: apps/web/lib/domain-connect/constants.ts:1-7
Dynadot Registrar Operations and Renewals
For domains provisioned or registered through Dub's partnership with Dynadot, backend routines manage domain purchases, availability searches, and annual renewals.
Sources: apps/web/lib/dynadot/client.ts:14-73
The DynadotClient extends HttpBaseClient to communicate with Dynadot's XML/JSON API (https://api.dynadot.com/api3.json), authenticating via query parameters (key: DYNADOT_API_KEY). Premium domain registrations are initiated by creating Stripe payment intents and recording pending invoices. Once payment succeeds, background workers finalize registrations and synchronize expiration dates.
Sources: apps/web/lib/dynadot/client.ts:14-73, apps/web/lib/api/domains/initiate-premium-domain-registration.ts:10-164
class DynadotClient extends HttpBaseClient {
protected readonly vendor = "Dynadot";
protected readonly baseUrl =
process.env.DYNADOT_BASE_URL || "https://api.dynadot.com/api3.json";
protected readonly redactedQueryParams = ["key"];
protected buildAuthHeaders() {
return {};
}
protected buildAuthQuery() {
return {
key: assertEnv("DYNADOT_API_KEY"),
};
}
...Sources: apps/web/lib/dynadot/client.ts:14-30
API Endpoints and Routing Reference
The Domain Management subsystem exposes several REST API routes for managing workspace domains, verifying configurations, and triggering automated setups.
Sources: apps/web/app/api/domains/route.ts:23-233
| Endpoint | Method | Description |
|---|---|---|
/api/domains | GET | Retrieves all domains associated with the authenticated workspace. |
/api/domains | POST | Adds a new custom domain or claims a .dub.link subdomain. |
/api/domains/[domain] | GET | Retrieves details and metadata for a specific workspace domain. |
/api/domains/[domain] | PATCH | Updates domain configuration (logos, asset links, auto-renewal options). |
/api/domains/[domain]/verify | GET | Checks Vercel domain verification status and discovers Domain Connect support. |
/api/domains/[domain]/domain-connect/apply | POST | Generates a signed Domain Connect URL for automated DNS setup. |
/api/domains/[domain]/forward-instructions | POST | Emails DNS setup instructions to a specified recipient. |
/api/domains/[domain]/validate | GET | Validates domain syntax, availability, and active site conflicts. |
Sources: apps/web/app/api/domains/route.ts:23-233, apps/web/app/api/domains/domain/route.ts:28-208, apps/web/app/api/domains/domain/verify/route.ts:16-139, apps/web/app/api/domains/domain/domain-connect/apply/route.ts:24-143
Error Handling and Invariant Enforcement
To protect multi-tenant boundaries and prevent unauthorized domain squatting, the subsystem enforces strict invariant checks across database transactions and API boundaries.
Sources: apps/web/app/api/domains/domain/route.ts:118-125
Caution
When updating a domain slug via PATCH /api/domains/[domain], if the domain is Dub-provisioned (registeredDomain exists), the update is immediately rejected with a forbidden error to prevent orphaned registrar records.
Sources: apps/web/app/api/domains/domain/route.ts:118-125
Warning
Cron verification routines (GET /api/cron/domains/verify) automatically track unverified domains. Domains failing verification past grace periods trigger reminder notifications or eventual deletion from the database.
Sources: apps/web/app/ee/api/cron/domains/verify/route.ts:9-14