Skip to content
Chapter 98Lesson 4

Custom domains and automatic SSL

Point a domain you own at your Vercel deployment with DNS records, and let Vercel provision and renew the HTTPS certificate for you.

Your app is live, but the address gives it away. your-project.vercel.app is a fine URL for the team, and you’ve been sharing the project alias since the first deploy, but it’s the wrong URL to put in front of a customer. It’s unbranded, it isn’t yours, and to anyone who has seen a few of them it reads as “not a real product yet.” Going live properly means a domain you own, resolving to your app, served over HTTPS with a padlock in the address bar.

If your mental image of “get a certificate and serve HTTPS” comes from older tutorials, that image is probably out of date. There is a version of this task that involves buying a certificate, generating a signing request with OpenSSL, uploading files, and setting a calendar reminder so the certificate doesn’t expire at 2 a.m. and take the site down. None of that is how it works in 2026. On Vercel, the entire certificate side comes down to two DNS records and no certificate work of your own: you point your domain at Vercel, and Vercel provisions, installs, and renews the certificate for you, indefinitely, for free. That is worth knowing up front, because it changes how you should approach the rest of this lesson. The hard part isn’t the lock, it’s the pointer.

This lesson covers four things, in order: the DNS records you set, the certificate Vercel handles for you, the one decision you make once and live with (apex versus www), and the one pitfall that catches teams who put Cloudflare in front of Vercel. Underneath all four is the question an experienced engineer is really asking while doing this: what is the minimum I have to configure, what does the platform handle on its own, and what fails while DNS is still mid-flight?

Before any clicking, get the model straight, because everything else is a special case of it. A live custom domain is two independent concerns that people new to this tend to conflate into one:

  • The pointer, DNS. The domain name has to resolve to Vercel’s edge: when a browser looks up app.example.com, the answer has to lead to Vercel. That answer is a DNS record you create at your registrar. This half is your job, and you do it once.
  • The lock, TLS. Browsers won’t serve a modern site over plain HTTP; the domain needs a valid certificate to be reachable over HTTPS. That’s TLS , proven by a TLS certificate . This half is Vercel’s job, and it’s fully automatic.

You already understand half of this model. In the first lesson of this chapter you learned that “production” isn’t a deployment, it’s a pointer: an alias Vercel re-aims at whichever immutable deployment is current. A custom domain just adds a second pointer, one hop upstream of the first. DNS points your domain at Vercel’s edge, and Vercel’s alias points its edge at the live deployment. A single request from a browser travels through both pointers in series.

app.example.com your domain
DNS record yours, set once
Vercel edge the platform
production alias Vercel's, re-aimed on every deploy
current deployment the live build
Two pointers in series. DNS (yours, set once) points the domain at Vercel's edge; the production alias (Vercel's, re-aimed on every deploy) points the edge at the current deployment.

Reusing the pointer idea is deliberate: you don’t have to learn a new mental model, you only have to extend one you already trust. Keep the two halves separate in your head for the rest of the lesson. When something goes wrong, it’s almost always the pointer that’s misconfigured or still propagating, never the lock, because the lock isn’t yours to misconfigure.

This is the one genuine decision in the lesson, and it’s worth pausing on because it’s effectively irreversible. You can flip it later, but flipping it after launch is a migration with redirect and SEO cost, the kind of thing nobody wants to schedule. So decide once, deliberately, now.

The choice is which form of your domain is the real one:

  • Apex is example.com, the bare domain with nothing in front. It’s the shortest, cleanest expression of your brand, and the modern default for a marketing site.
  • www is www.example.com. It’s historically easier to configure, for the reason you’ll see in the next section, and some large sites still prefer it on that basis.

The rule that matters more than the choice itself is this: pick one as canonical and redirect the other to it. Never serve your site at both addresses as if they were equals. If both example.com and www.example.com independently serve the same content, search engines see two different sites with identical pages. That’s duplicate content, which dilutes your ranking, and your inbound links fragment across two addresses instead of accumulating on one. The fix is a permanent redirect (a 301 or 308) from the non-canonical form to the canonical one. Vercel adds this redirect for you automatically once you’ve added both forms and marked one as the primary.

For this course, the default is apex canonical: example.com is the real address, and www.example.com permanently redirects to it. That’s the cleanest brand URL, and it’s the convention assumed from here on.

One forward-looking note, so the shape of a real SaaS doesn’t surprise you later. The apex isn’t the only name you’ll eventually serve. A common split puts the marketing site on the apex, the application itself on app.example.com, and documentation on docs.example.com: three subdomains, three purposes. Further out, multi-tenant products give each customer their own subdomain, like acme.example.com and globex.example.com, provisioned dynamically. That per-tenant routing is its own substantial topic for later in the course, so just keep it in mind and don’t let it complicate the decision in front of you now. Today you’re wiring one domain.

Before the mechanics, make the decision concrete.

You’re launching the marketing site for a new product and want the cleanest brand URL you can put on a business card. How should you wire example.com and www.example.com?

Treat example.com as the real address and have www.example.com permanently redirect to it.
Serve identical content at both addresses so visitors can reach the site whether or not they type the www.
Use www.example.com as the real address, since a bare domain like example.com can’t be pointed at Vercel at all.
Make example.com the real address and turn www.example.com into its own standalone landing page.

The two DNS records, and why apex is the awkward one

Section titled “The two DNS records, and why apex is the awkward one”

This is where first-timers get stuck, so go slowly and lead with the reasoning, not with a record to copy. The confusion all comes from one quirk: the cleanest kind of DNS record is forbidden at exactly the address most people want to use.

Start with the easy case. For www, or any subdomain at all, you create a CNAME . A CNAME says “this name is really an alias for that other name; go look that one up instead.” You point www.example.com at the target Vercel gives you, and you’re done. CNAMEs are standard, supported by every registrar, and they track changes automatically: if Vercel ever moves the underlying address, the CNAME still resolves correctly because it points at a name, not a fixed address.

Now the apex , where the quirk lives. The DNS specification forbids a CNAME at the apex, and the reason is structural. The zone root has to coexist with a couple of mandatory records that define the zone itself (its SOA and NS records), and the rules say a CNAME can’t share a name with any other record. Since example.com already has those records living on it and can’t give them up, it categorically cannot also be a CNAME. The clean tool is off the table at exactly the address you most want to use.

There are two ways around it:

  1. An A record. An A record points the apex straight at Vercel’s IP. This always works, everywhere. The catch is that you’re now hardcoding a specific address, and that address is Vercel’s to change, so you copy the current value from your dashboard rather than memorizing it. To make one IP serve every visitor on earth quickly, Vercel uses anycast , which is how a single A-record address can be fast from anywhere.
  2. An ANAME / ALIAS record. This is a special record type that some registrars offer. It gives you CNAME-like behavior at the apex: you point it at Vercel’s name, and it auto-tracks any address change, just like a real CNAME would. When your registrar supports it, prefer it, because it gives you the A record’s benefits without the hardcoded address.

So the rule of thumb for the apex is: use ANAME/ALIAS if your registrar offers it, and fall back to the A record if it doesn’t.

One thing matters more than any specific value here, and it’s the durable lesson of this section: never treat a particular Vercel IP or CNAME target as authoritative. Vercel issues these per project now and rotates them, so the value for your project may not match one you saw in someone else’s tutorial, and a value that’s correct today may change. The instruction that survives is to copy whatever Settings → Domains shows you for this specific project. Everything below is a clearly labeled example, never a string to memorize.

| Type | Name | Value | TTL | | --- | --- | --- | --- | | CNAME | www | <project>.vercel-dns-NNN.com | 300 |

The Value is an example: copy your per-project value from Settings → Domains, never from a tutorial.

A subdomain is the easy case: one CNAME aliasing the name to whatever Vercel shows you.

The figure has two tabs rather than one table to make the point of this section visual: a subdomain is one clean row, while the apex is the awkward special case with two fallback options. Once you understand why the apex is different, you’ll never again wonder why your www setup just worked while the bare domain took more thought.

In practice you don’t go hunting for these values; Vercel hands them to you. The flow is short.

  1. In your project on Vercel, go to Settings → Domains and enter the domain you want to add (start with the apex, example.com).

  2. Vercel shows you the exact record or records to create: the type, the name, and the value, scoped to your project. This is the value you copy, and it’s the authoritative one, not anything from a tutorial.

  3. Create those records at your registrar, wherever you bought the domain, since that’s where DNS lives.

  4. Then wait. Vercel polls your DNS in the background and flips the domain’s status from Invalid Configuration to Valid Configuration once it sees the record. You don’t click anything to make this happen.

Vercel’s Settings → Domains panel. The status pill is the thing you watch: it flips from Invalid Configuration to Valid Configuration on its own once your DNS record is visible. No button to press.

Propagation, and the automatic certificate

Section titled “Propagation, and the automatic certificate”

You created the record, the dashboard still says Invalid Configuration, and nothing seems to be happening. This is the moment that makes people thrash: re-saving the record, deleting and re-adding it, second-guessing the value. None of that helps. Almost always nothing is broken; you’re just inside the wait.

The wait is called propagation . When you change a record, the new value isn’t instantly true across the internet. Resolvers all over the world have cached the previous answer, and they’ll keep serving it until their cache expires. How long they hold it is governed by the record’s TTL . So the gap between “saved at the registrar” and “Vercel sees it” can be seconds or hours, and the ceiling is set by the old record’s TTL still living in caches around the world. Vercel polls and updates the status pill on its own, so your job during this window is to wait, not to edit.

There’s a move that makes future changes painless: lower the TTL before you make a change, then raise it back after. Think of TTL as a dial you turn down before the change and up again afterward. A day before you plan to change or cut over a record, drop its TTL to something small, like 300 seconds. Caches now hold the old value for only five minutes, so when you flip the record the change propagates fast and the cutover window is short. Once everything’s stable, raise it back to an hour or more so resolvers cache efficiently again and you’re not generating needless lookups. You can’t shrink the wait for this change retroactively, since the old TTL already set it, but you can set up the next one to be quick.

Now the part this lesson promised in its first paragraph. The moment your DNS resolves to Vercel, Vercel automatically requests a TLS certificate from Let’s Encrypt , installs it on your domain, and renews it before it expires. There’s no signing request, no file upload, no cron job to remember, and no renewal outage at 2 a.m. The entire historical certificate ritual collapses into a single instruction: wait for the status to go green. (Uploading your own custom certificate is an Enterprise-only feature, and you will almost certainly never need it. The automatic path is the one to take.)

One piece of HTTPS is not fully automatic, and it’s worth flagging now so it doesn’t surprise you later. Vercel automatically redirects plain HTTP to HTTPS on custom domains, so visiting http://example.com bounces you to https://. But the header that tells browsers to never even try plain HTTP again, Strict-Transport-Security, or HSTS , is an application-level response header, and that one is your job, not the platform’s. You don’t write it here. It lives in next.config.ts alongside your other security headers, and you’ll set it and verify it in the launch-checklist lesson at the end of this chapter. For now, hold one clean distinction: the HTTP-to-HTTPS redirect is automatic, while the HSTS header is yours and comes later.

Putting Cloudflare in front without breaking TLS

Section titled “Putting Cloudflare in front without breaking TLS”

This is the pitfall, and it’s the kind that stays invisible until someone audits it, which makes it exactly the sort of thing an experienced engineer keeps on a checklist. Set the framing straight first, though, because the recommendation has shifted.

In 2026, Vercel itself discourages putting a Cloudflare proxy in front of Vercel. Proxying through Cloudflare blinds Vercel’s own Firewall and bot protection to real client traffic, since Vercel then sees Cloudflare’s IPs rather than your visitors’; it adds a network hop of latency; and it complicates caching. Vercel’s built-in Firewall is the default edge-security answer for a 2026 SaaS, and you should reach for it first. So treat this section as conditional: the default is not to run Cloudflare in front of Vercel. Teams still do it deliberately for specific reasons, such as an existing investment in Cloudflare’s WAF rules or multi-origin edge logic Vercel doesn’t cover, and if you’re one of them, here is the one rule that keeps the setup from being silently insecure.

When you front Vercel with Cloudflare, you move your domain’s nameservers to Cloudflare and let it proxy requests through to Vercel (the “orange cloud”, or proxy-on, mode). The thing to understand is what that does to the lock. You no longer have one TLS connection; you have two TLS hops end to end:

  • Browser to Cloudflare, encrypted with Cloudflare’s own edge certificate.
  • Cloudflare to Vercel, a second, separate connection secured by Vercel’s origin certificate, the Let’s Encrypt one from the previous section.

That’s two hops, two independent certificates, two separate terminations. The pitfall is that beginners model this as one connection with one lock, when it’s really two connections that each need their own lock. Whether that second hop is actually locked depends entirely on one Cloudflare setting, the SSL/TLS encryption mode. It has three settings that matter, and only one is correct:

  • Flexible leaves the Cloudflare-to-Vercel hop as plain, unencrypted HTTP. The browser still shows a padlock, because the first hop (browser to Cloudflare) is encrypted, but your traffic crosses the public internet between Cloudflare and Vercel in the clear. Worse, Vercel is HTTPS-only and will try to redirect the plain request to HTTPS, which gives you a redirect loop. This is wrong and insecure.
  • Full encrypts the origin hop, but Cloudflare does not validate Vercel’s certificate. The traffic is encrypted, yet Cloudflare will accept any certificate on the far end, which means the connection is spoofable. It’s better than Flexible, but still not safe.
  • Full (strict) encrypts the origin hop and validates Vercel’s certificate. This is the only mode where the connection is genuinely encrypted and verified end to end.
Browser the visitor
TLS Cloudflare edge cert
Cloudflare edge the proxy
TLS Vercel (Let's Encrypt) cert
Vercel edge the origin
Two independent TLS terminations, not one. Full (strict) is the only Cloudflare mode where both arrows are encrypted and Vercel's certificate is validated.

What makes this a genuine senior-level distinction is that from the browser, the padlock looks identical in all three modes. With Flexible, Full, or Full (strict), the user sees the same lock every time. Only Full (strict) is actually end-to-end secure, and the difference is invisible unless someone deliberately inspects that second hop. That’s why it slips into production and sits there: nothing looks wrong.

Then practice spotting the trap, because spotting it is the whole skill.

Each claim is about running Cloudflare in front of Vercel. Mark each statement True or False.

The browser shows a padlock, so the connection is encrypted end to end.

The padlock only proves the browser → Cloudflare hop is encrypted. On “Flexible” mode the Cloudflare → Vercel hop is plain HTTP — encrypted to the user’s eye, in the clear on the wire. The correct answer is False.

“Full (strict)” is the only Cloudflare SSL/TLS mode that both encrypts the origin hop and validates Vercel’s certificate.

Flexible leaves the origin hop unencrypted; Full encrypts it but accepts any certificate (spoofable); only Full (strict) encrypts and verifies. The correct answer is True.

Putting Cloudflare in front of Vercel is the recommended default for a 2026 SaaS.

Vercel discourages it — the proxy blinds Vercel’s own Firewall and adds latency. Vercel’s built-in Firewall is the default; Cloudflare-in-front is a deliberate exception for specific needs. The correct answer is False.

One operational footnote while you’re moving domains around. If the domain you’re adding is already attached to a different Vercel project, Vercel may ask you to prove you control it by adding a TXT verification record at your registrar. Add it, let Vercel verify, and then leave it in place: Vercel re-checks it periodically, so deleting it later can break the domain’s attachment. It’s an edge case rather than part of the main flow, but it surprises people the first time they see it.

A domain isn’t “done” just because the dashboard turned green and it loaded once in your browser. “Done” is something you can prove, from outside your own machine, with a handful of commands, and that proof is the durable artifact you walk away with. This is the same checklist-as-gate idea that runs through this whole chapter, and the launch-checklist lesson at the end will lean directly on it.

Here are the five checks. The first four are commands with a clear pass condition, and the fifth is the human one.

Terminal window
dig +short example.com @1.1.1.1 # returns Vercel's IP, not your old host's
curl -sI https://example.com # HTTP/2 200, no certificate error
curl -sI http://example.com # 308 (or 301), Location: https://example.com
curl -sIL https://www.example.com # follows the redirect down to the apex
# then open it in a browser: padlock present, click around

Each command earns its place, and the reasoning is the part worth internalizing:

  1. DNS resolves to Vercel. dig with @1.1.1.1 asks Cloudflare’s public resolver for the answer, deliberately bypassing your own machine’s cache. This is the single most important habit in the list: querying from outside your laptop dodges the stale answer your own resolver may still be holding, which is the number-one source of “it works for me but not for them.” If this returns Vercel’s address, the pointer is real.

  2. HTTPS serves a valid certificate. curl -sI makes a request and prints only the response headers (-I is headers-only; you don’t need the page body, just the status line and confirmation that there’s no certificate error). A clean 200 with no TLS complaint means the lock is in place.

  3. HTTP redirects to HTTPS. The same curl -sI against the plain http:// address should come back 308 (or 301) with a Location header pointing at https://. This proves Vercel’s automatic HTTP-to-HTTPS redirect is doing its job.

  4. The canonical redirect works. curl -sIL against www.example.com, where -L follows redirects all the way down, should land on the apex. This proves your apex-versus-www decision is actually wired: the non-canonical form really does redirect to the canonical one.

  5. Browser sanity check. Load it like a human would, confirm the padlock, and click around. Automated checks prove the plumbing; a real load proves the experience.

One habit ties these together: verify from outside your own machine. Your laptop can mislead you, because it has caches, it has its own resolver, and it may have visited the old site five minutes ago. A public resolver and a plain curl see what your customers see. Learning to check from the outside rather than the comfortable inside is the part of this lesson that outlives Vercel.

A closing word for the case where this domain is already live somewhere else and you’re cutting it over to Vercel, because that’s a real operation with real downtime risk. Lower the TTL a day ahead so the cutover propagates in minutes rather than hours. Prepare the Vercel records before you flip anything, so the new target is ready the instant you change the pointer. Expect a window of partial propagation where some visitors hit the new site and some still hit the old one, and remember that the certificate provisions only after DNS resolves to Vercel, so there’s a short beat between “DNS points here” and “HTTPS works here.” Do the cutover during low traffic. And keep the old DNS records on hand: reverting the DNS pointer is your rollback for a domain cutover gone wrong, the same recovery instinct that runs through this chapter, applied to the pointer instead of the deployment.