Skip to main content
doc0blade47/dubdocumentation home
Sign in

Domain Management

Last updated Oct 12, 2026
Relevant source files

The following files were used as context for generating this wiki page:

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 / ParameterValue / Description
DUB_CUSTOM_DOMAIN_A_RECORD76.76.21.21 (Target IP for apex domains)
DUB_CUSTOM_DOMAIN_CNAMEcname.dub.co (Target host for subdomains)
DOMAIN_CONNECT_KEY_HOST_dck1 (TXT record key host for Domain Connect)
DEFAULT_DC_SERVICE_APEXlinks-apex (Service ID for apex configuration)
DEFAULT_DC_SERVICE_SUBDOMAINlinks-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

EndpointMethodDescription
/api/domainsGETRetrieves all domains associated with the authenticated workspace.
/api/domainsPOSTAdds a new custom domain or claims a .dub.link subdomain.
/api/domains/[domain]GETRetrieves details and metadata for a specific workspace domain.
/api/domains/[domain]PATCHUpdates domain configuration (logos, asset links, auto-renewal options).
/api/domains/[domain]/verifyGETChecks Vercel domain verification status and discovers Domain Connect support.
/api/domains/[domain]/domain-connect/applyPOSTGenerates a signed Domain Connect URL for automated DNS setup.
/api/domains/[domain]/forward-instructionsPOSTEmails DNS setup instructions to a specified recipient.
/api/domains/[domain]/validateGETValidates 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

Was this page helpful?