DEV Community

magnusberg2958
magnusberg2958

Posted on

Custom Domain Onboarding UX: 2 Record Handoff Modes Explained for 2026

Short answer: For custom domain onboarding in 2026, show every customer the exact DNS records to copy, offer to write them only after proving narrow zone authority, and never call the cutover complete until independent DNS observations meet the service-level objective.

That ordering matters for an edtech platform moving zones away from a registrar-specific API. The primary trade-off is propagation delay versus cutover speed: an automated write can shorten the customer's part of the workflow, but it cannot make DNS caches converge on command. The UX has to expose that distinction without making a school administrator learn resolver internals.

The incident lesson: acceptance is not propagation

Consider a bounded production scenario: a school owns courses.example.edu, the learning platform serves the application, and the existing onboarding flow depends on one registrar's API. During a migration, the write request is accepted, yet a campus resolver can still return the earlier answer. That is not proof that the write path failed. It is proof that “the control plane accepted a change” and “students can observe the new destination” are different claims, separated by authoritative publication, resolver caches, delegation, and the TTLs already in circulation. Treating the first claim as the second creates a particularly ugly cutover: the dashboard turns green, support closes the change, and a portion of users continue reaching the old site while the platform team has already started removing the old route.

Don't collapse those clocks.

The invariant is operational: store the intended RRset, the observed RRset, the resolver vantage point, and the observation time. Keep the previous serving path available until the observation SLO is satisfied. A 300-second TTL can be a useful planning input, but it isn't a promise that every recursive resolver will show the new answer in exactly five minutes. Negative answers may have been cached too, so onboarding a name that did not previously exist needs the same measured verification as changing an existing name.

I initially prefer the fastest-looking path when capacity planning says a support queue will spike during a semester launch; the correction is to count operator minutes and rollback exposure, not button clicks. A write API may remove two minutes of customer work while adding credential lifecycle, provider-specific error handling, audit storage, and a larger on-call surface. I'm not sure which side wins for a given school portfolio until the team has the zone count, change frequency, permission model, and support-volume data. Your mileage may vary.

What should custom domain onboarding UX show customers to copy or write?

Show one canonical desired record set first. Each row needs the record type, owner name, value, TTL, and purpose, with a copy control that preserves the value exactly. The owner deserves special care because DNS consoles disagree about whether users enter an apex marker, a relative label, or a fully qualified name; the onboarding service should retain one canonical machine representation while its display layer explains what the customer must enter. After submission, label the state precisely: “change requested,” “observed at authoritative nameserver,” and “observed by verification resolvers” are useful claims. “Ready” is useful only after the dependencies required by the application are also ready.

Tiny labels matter.

For records such as a DMARC policy, RFC 7489 specifies publication as a DNS TXT record at the _dmarc label. Preserve the TXT content instead of casually reformatting it, show the existing RRset before replacement, and make ownership of the change explicit. The same UI discipline applies to a domain-verification TXT value or a routing CNAME even though their application semantics differ: render the exact desired value, retain evidence of what was observed, and do not infer success from a control-plane acknowledgement.

Offer the write mode only when the customer has authenticated authority over the precise zone and can approve the exact diff. The operation should be idempotent, scoped to the intended records, attributable in an audit log, and reversible through a recorded prior state. A preview is mandatory. When those conditions aren't available, the honest fast path is good copy UX plus active verification, not an automation button backed by broad account credentials.

This also changes error handling. A malformed desired record can be rejected before either workflow begins; an unobserved record remains pending and should be checked again; an observed DNS answer can advance to the next dependency, such as certificate issuance or HTTP routing. Retries belong to the individual state transition. They don't belong to a single opaque “set up my domain” request that leaves support guessing which action already happened.

An observable cutover path and its capacity cost

The preventative code path is a provider-neutral observer. It records evidence rather than treating a successful mutation response as the finish line. This Go example checks TXT data because TXT is common in ownership and mail-policy workflows; a production implementation should use type-specific comparisons and query the authoritative nameservers as well as deliberately selected recursive resolvers.

package dnscheck

import (
    "context"
    "fmt"
    "net"
    "time"
)

type Expected struct {
    Name  string
    Value string
}

type Observation struct {
    Name       string
    Value      string
    ObservedAt time.Time
}

func ObserveTXT(ctx context.Context, expected Expected, timeout time.Duration) (Observation, error) {
    deadline, cancel := context.WithTimeout(ctx, timeout)
    defer cancel()

    values, err := net.DefaultResolver.LookupTXT(deadline, expected.Name)
    if err != nil {
        return Observation{}, fmt.Errorf("observe TXT %q: %w", expected.Name, err)
    }

    for _, value := range values {
        if value == expected.Value {
            return Observation{
                Name:       expected.Name,
                Value:      value,
                ObservedAt: time.Now().UTC(),
            }, nil
        }
    }

    return Observation{}, fmt.Errorf("expected TXT value not observed for %q", expected.Name)
}
Enter fullscreen mode Exit fullscreen mode

That's it.

The loop around this function is where the real system lives. Persist the desired state before asking anyone to mutate DNS. Schedule observations with bounded backoff, attach the resolver identity and timestamp, and emit metrics for time spent in each onboarding state. Page on threats to a user-facing cutover SLO or on a stuck cohort, not on one failed lookup; DNS observations can be inconclusive without indicating an application incident. For capacity planning, estimate concurrent pending domains at launch time, queries per verification cycle, retained evidence per observation, and support contacts per manual handoff. Those inputs determine worker count and storage far more honestly than a promise of “instant setup.”

The application health model must remain separate. A name can resolve correctly while certificate issuance or HTTP routing is still pending, and a mail-related TXT record can be visible while its policy effect depends on other mail configuration. Give each dependency its own state and timestamp. This creates more states in the data model, but it creates fewer ambiguous tickets.

Approach Cutover speed Platform burden Best fit Boundary
Show records to copy Customer-paced Verification and support Shared accounts, delegated zones, change approval Typos and owner-name confusion add delay
Scoped write integration Fast after consent Credentials, adapters, audit, rollback Repeated changes across many controlled zones Provider permissions and schemas vary
Retain the registrar-specific path Fast for current accounts Existing adapter and lock-in remain A short transition with no migration capacity It postpones portability
Self-host authoritative DNS Team-controlled Full service ownership and on-call load DNS is a deliberate platform competency Usually excessive for onboarding alone

This is a buy-versus-build decision with an SLO attached, not a frontend preference. Managed writes transfer some implementation work but retain integration and credential risk. Building a provider abstraction buys control while committing the team to adapter maintenance. Copy-only transfers the mutation to the customer while keeping authority boundaries clean. None erases propagation delay.

The edtech decision rule and its limits

Choose scoped writing when the zone owner is authenticated, the proposed RRset is visible before mutation, credentials are limited to the required scope, the action is idempotent and audited, rollback state is retained, and independent observations gate the cutover. If one condition is missing, show the records to copy and verify them continuously. For an exam portal, preserve the old serving path until the cutover SLO is met; for a low-risk faculty microsite, a slower customer-managed handoff may be a reasonable reduction in platform complexity.

The catch is clear: copy-only onboarding is not suitable when a customer operates hundreds of zones through a staffed DNS team and expects approved bulk changes. Use a signed change plan or a narrowly authorized write integration there. Automated writing is not suitable for schools with shared registrar accounts, delegated subzones the credential cannot safely distinguish, or formal change freezes; stick with copy, explicit approval, and observation in those cases. Self-hosting authoritative DNS deserves consideration only when ownership, staffing, and failure-domain requirements justify carrying the service on call.

No green light on submission alone.

The useful product contract is narrower and more defensible: the platform states what record it expects, who was asked to change it, what each observer actually returned, and which downstream dependency has passed. That contract lets an edtech team remove a registrar-specific API without pretending DNS is transactional, and it gives support a precise answer when the customer's console says “saved” while students still resolve the previous destination.

Sources

Top comments (0)