Technical SEO every developer needs to know
SEO isn’t just the marketer’s job
Most devs ship sites without thinking about SEO. Then the client hires a marketing agency that says “the site needs technical adjustments” and charges $1-3k to do what should have been done during development.
I’ve seen this happen with clients who came to me with an agency-built site that was “ready” but didn’t show up on Google. Generic meta tags, no Schema.org, no sitemap, no Open Graph. The designer nailed the visuals, the dev implemented it faithfully, and nobody thought about how Google would read the thing.
Technical SEO is the dev’s responsibility. You don’t need to become a marketing expert. You need to deliver the basics done right. And the basics get you 80% of the results.
Meta tags: the bare minimum every page needs
Title and Description
<title>Page Title | Company Name</title>
<meta name="description" content="Clear description of the content in up to 160 characters">
The <title> shows up in two places: the browser tab and the Google search result (the blue clickable text). The description shows up as the summary below the title on Google.
If you don’t set these, Google makes them up based on the page content. And it usually does a bad job. It grabs a random snippet that might not make sense out of context.
Practical rules:
- Title with 50-60 characters. More than that and Google cuts it off with ”…”
- Description with 140-160 characters. Too long gets cut. Too short wastes space
- Every page needs a unique title and description. Copying the same text across all pages is as bad as not having them at all
- Main keyword in the title and description. If the page is about “veterinary clinic in Austin”, those words need to be in the title
On the Laura Nasralla project, the title is “Veterinary Clinic in Ribeirao Preto | Dr. Laura Nasralla”. Short, with a local keyword, and the professional’s name. On Google, anyone searching “vet Ribeirao Preto” sees exactly what they’re looking for.
Open Graph
For when someone shares the link on WhatsApp, LinkedIn, Twitter or Facebook:
<meta property="og:title" content="Title">
<meta property="og:description" content="Description">
<meta property="og:image" content="/og-image.png">
<meta property="og:type" content="website">
<meta property="og:url" content="https://yoursite.com/page">
Without og:image, the link preview has no image. On WhatsApp, a link without an image looks like spam. A link with a well-made image looks professional.
The ideal OG image: 1200x630px, PNG or JPG. Put the logo, company name and a short phrase. It doesn’t need to be a masterpiece. It needs to exist.
Tip: create a generic OG image for the site and specific images for important pages (home, each service, each blog post). Tools like Figma or Canva can do this in minutes.
Heading hierarchy
<h1>Only one per page</h1>
<h2>Main section</h2>
<h3>Subsection</h3>
<h2>Another main section</h2>
H1 is the page title. One per page, no exceptions. H2 divides the main sections. H3 subdivides. Don’t skip levels (H1 straight to H4 without H2 and H3 in between).
Google uses this hierarchy to understand the content structure. Messy hierarchy = Google doesn’t understand what’s most important on the page. Result: worse rankings.
Common mistake: using H1 in multiple places because “the font looks nice”. Headings are semantic, not styling. Want a big font? Use CSS. Want correct hierarchy? Use headings in the right order.
Schema.org: speaking Google’s language
JSON-LD in the <head> that tells Google exactly what that page represents. It’s structured data that Google reads and uses to build search results.
LocalBusiness (for local businesses)
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Family Pilates e Fisioterapia",
"address": {
"@type": "PostalAddress",
"streetAddress": "Rua Exemplo, 123",
"addressLocality": "Curitiba",
"addressRegion": "PR",
"postalCode": "80000-000",
"addressCountry": "BR"
},
"telephone": "+5541999999999",
"url": "https://familypilates.com.br",
"geo": {
"@type": "GeoCoordinates",
"latitude": "-25.4284",
"longitude": "-49.2733"
},
"openingHours": "Mo-Fr 07:00-21:00"
}
This is what makes a business show up on Google Maps and in local results. On Laura Nasralla (a vet clinic in Ribeirao Preto), I implemented LocalBusiness with exact coordinates and business hours. On Family Pilates, same thing for Curitiba.
A dev who ships a site for a local business without Schema.org LocalBusiness is delivering incomplete work. The client will spend $1-3k on an SEO agency to implement what should have come with the site.
Other useful types
Organizationfor companies that aren’t local businesses (SaaS, remote consulting)Article/BlogPostingfor blog posts. Includes author, publication date, update date. Google uses this to show dates in search resultsProductfor product pages. Price, availability, reviewsFAQPagefor FAQ pages. Google can show the questions directly in search results (rich snippets)BreadcrumbListfor breadcrumb navigation. Shows the path in search results
Each type is a different JSON-LD block in the <head>. Implementation takes minutes per type. The impact on search results can be big: rich snippets (expanded results) have much higher click-through rates than normal results.
Sitemap and robots.txt
Sitemap.xml
A file that lists all the site’s pages for Google. It’s a map that says “these are the pages that exist, please index all of them”.
In Astro, install @astrojs/sitemap and it generates automatically on build. Zero manual configuration.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://yoursite.com/</loc></url>
<url><loc>https://yoursite.com/services</loc></url>
<url><loc>https://yoursite.com/cases</loc></url>
</urlset>
After generating it, register it in Google Search Console. Go to “Sitemaps”, paste the URL (usually https://yoursite.com/sitemap.xml), and submit. Without this, Google discovers the pages on its own, but it can take weeks.
robots.txt
User-agent: *
Allow: /
Sitemap: https://yoursite.com/sitemap.xml
A file at the site root that tells Google what it can and can’t index. The version above is the most common: “index everything, and here’s the sitemap”.
If there are pages that shouldn’t be indexed (admin panel, staging page, test area), add Disallow:
User-agent: *
Disallow: /admin
Disallow: /staging
Sitemap: https://yoursite.com/sitemap.xml
Core Web Vitals: the metrics Google actually uses
Google doesn’t rank just by content. It ranks by experience. And it measures experience with three metrics:
LCP (Largest Contentful Paint)
How long it takes for the largest visible element on the page to load. Usually the hero image or the main text block. The target is under 2.5 seconds.
The usual culprit is an unoptimized 3 MB hero image, a font blocking rendering, or a slow server. Fix it with image optimization, font-display: swap, and hosting with a CDN.
INP (Interaction to Next Paint)
How long the browser takes to respond when the user clicks, taps or types. Measures responsiveness. The target is under 200ms.
The usual culprit is heavy JavaScript blocking the main thread, or an entire framework hydrating on load. Fix it with less JavaScript, defer/async on scripts, and Astro instead of React for static sites.
CLS (Cumulative Layout Shift)
How much the layout “jumps” during loading. That effect where you click a button and it moves because an image loaded above it. The target is under 0.1.
The usual culprit is images without defined width/height, a font that loads late and changes text size, or a cookie banner that pushes content down. Fix it with explicit dimensions on all images and iframes, font-display: swap with preload, and a fixed banner that doesn’t push layout around.
SSG vs SSR vs SPA: impact on SEO
Your stack choice directly impacts how Google sees your site.
SSG (Static Site Generation) generates HTML at build time. Best for SEO. Google receives ready-made HTML and indexes it immediately. Astro does this natively.
SSR (Server-Side Rendering) generates HTML on each request on the server. Good for SEO (Google receives HTML), but slower than SSG because it generates on the fly. Next.js does this.
SPA (Single Page Application) renders everything on the client via JavaScript. The initial HTML is nearly empty. Google needs to execute JavaScript to see the content, and it doesn’t always do that. Plain React (Create React App, Vite) generates SPAs.
If SEO is a priority, SSG is the best option. If you need dynamic data per request (personalized pricing, region-based content), SSR. SPA only for webapps where SEO doesn’t matter (dashboards, internal panels).
That’s why AutoPars (a React SPA) needed a separate landing page in Astro. The marketplace is an SPA because it needs interactivity. The LP is SSG because it needs SEO. Each part on the right stack.
Canonical URL
<link rel="canonical" href="https://yoursite.com/page">
Tells Google which URL is the “official” one for that page. Important when the same page can be accessed through different URLs (with and without www, with and without trailing slash, with UTM parameters).
Without canonical, Google might treat them as different pages and split authority between them. With canonical, all authority is concentrated on the URL you defined.
Delivery checklist
- Unique title and description per page
- Open Graph with image on all pages
- Single H1 per page, correct hierarchy (H1 > H2 > H3)
- Schema.org matching the business type
- Sitemap.xml generated and registered in Search Console
- robots.txt at the root
- Images with descriptive alt text
- Core Web Vitals passing (Lighthouse 90+)
- HTTPS active
- Canonical URL defined on all pages
- Hreflang if the site is bilingual
This takes less than an hour on an Astro site. Everything I listed is configuration in the <head> and in the build. It’s not extra work. It’s work that’s part of the delivery.
It’s the difference between the first page of Google and the fifth. Between showing up on Maps and not existing.