Before this site had any traffic, it had a decision to make that most people make by accident: is the site at hibabuilds.com or www.hibabuilds.com?
Both resolve. That is the trap. If Google can reach the same page at two hosts, it has to choose one as canonical, and if you have not told it which, it guesses. Sometimes it guesses the one you do not link to, and your Search Console data splits across two properties.
What Google says the signals are
Google's canonicalization document lists the methods you can use and how much weight each carries.
Redirects are “a strong signal that the target of the redirect should become canonical.”
rel="canonical" is “a strong signal that the specified URL should become canonical.”
Sitemap inclusion is “a weak signal that helps the URLs that are included in a sitemap become canonical.”
And the line that decides how you set things up: the methods “can stack and thus become more effective when combined.” You do not pick one. You do all three and point them at the same host.
Separately, Google prefers HTTPS over HTTP as canonical on its own, unless the HTTPS page has a bad certificate, insecure dependencies, or redirects back to HTTP.
How this site does it
I chose the apex, hibabuilds.com, with no www. Then three things enforce it.
Both hosts are attached to the Vercel project, and the Next.js config has a permanent redirect that matches any request whose host is www.hibabuilds.com and sends it to the same path on the apex. That is the redirect signal, and because it is in the code rather than only in a dashboard, it travels with the site.
In the site config, the URL that everything else is built from is normalized before use. If the environment gives it www.hibabuilds.com, it strips the www. If it gives it http, it forces https. Every canonical, every Open Graph URL, every sitemap entry comes out of that one function, so they cannot disagree with each other.
Every page sends <link rel="canonical"> pointing at its apex URL. That is the second strong signal.
The sitemap lists only apex URLs. Weak signal, but it agrees with the other two, and agreement is the point.
I wrote about the day this config threw ERR_INVALID_URL in a blank environment variable broke my Vercel build. The normalize function exists because of that afternoon.
The three things Google says not to do
The document has a short list of mistakes, and I have seen all three recommended in forums.
Do not use robots.txt to block the version you do not want. Google cannot see the canonical hint on a page it is not allowed to crawl, so blocking the www host does not tell Google the apex is canonical. It just hides one copy.
Do not use the URL removal tool for canonicalization. It removes URLs from results. It does not consolidate them.
Do not use noindex on the duplicate as a way to pick a canonical. Same reason. It is a removal signal, not a preference.
And do not send different canonicals through different methods. If the redirect goes to the apex and the rel="canonical" says www, you have told Google two things and it will pick one.
Trailing slashes and the rest
The same logic applies to smaller variants: /articles/ versus /articles, uppercase versus lowercase, tracking parameters. Next.js normalizes the trailing slash by default. Everything else on this site is generated from slugs I control, so the variants do not exist to begin with. That is the cheapest canonicalization there is: never create the duplicate.
Source: Google Search Central, “How to specify a canonical with rel="canonical" and other methods.”