Documentation
Build & deploy
The build produces a folder of static files. Any host that serves files will serve a Vertex site — but the routing rules you give that host decide whether search engines see your pages or your homepage repeated.
What the build produces
build:ssg pre-renders every route to its own HTML file, so /about is a real document at a real path rather than a shell that fetches its content. Alongside the pages it writes the SEO surface and a pre-rendered 404.
dist/
index.html
about/index.html
docs/content/index.html
404.html # your chrome, carrying noindex
sitemap.xml # drafts omitted
robots.txt # drafts disallowed
manifest.json
assets/ # hashed JS, CSS, and image variantsBrand assets
generate:public-assets reads three source files from fixed paths and populates public/ from them. The lookup is by exact path, not a glob — an asset in the wrong place is silently skipped, and the script falls back to generating a letter-glyph favicon from your site title.
public/ is generated output. Don't edit it and don't commit it.
- site/favicon.ico — multi-resolution ICO (16/32/48/64)
- site/og-image.jpg — social share card, 1200×630
- site/assets/img/logo.png — JSON-LD organization logo and manifest icon, 512×512
Images
Put originals in site/assets/img/ and reference them by name. At build time the plugin generates AVIF, WebP, and JPEG variants at six widths, caches them under node_modules/.cache/ rather than in your repo, and serves them through a picture element with a srcset. Nothing to commit, nothing to regenerate by hand, and removing a source evicts its orphaned variants.
The matrix is configurable per site if the defaults are wrong for your imagery.
{
"imageVariants": {
"widths": [400, 800, 1200, 1600, 2000, 2400],
"formats": ["avif", "webp", "jpg"],
"quality": 80
}
}Hosting rules that matter
Vertex output is genuinely static, so the host should serve each pre-rendered file directly and send only unmatched paths to the 404 page.
The failure mode to avoid is the single-page-app rewrite — a catch-all sending every path to /index.html with a 200. On a pre-rendered site that serves the homepage for every URL. Each page then reports the homepage's title and canonical, and search engines file the whole site as duplicate content or soft 404s. The pre-rendered files are right there; let the host serve them.
- Do: serve existing files directly, and route unmatched paths to /404.html.
- Don't: rewrite /<*> to /index.html at status 200.
Deploying to AWS Amplify
Amplify builds from the repo and needs two custom rules: one canonicalizing www to the apex domain, and one catch-all pointing at the pre-rendered 404.
Worth knowing: Amplify implements a 404-status rule as a 302 redirect to the target rather than serving the body at the original URL. That's the best its rule engine offers — removing the rule is worse, because Amplify has no native 404.html fallback and unmatched paths return an empty body instead.
[
{
"source": "https://www.example.com",
"target": "https://example.com",
"status": "301"
},
{
"source": "/<*>",
"target": "/404.html",
"status": "404"
}
]Trailing slashes
Because the build emits nested directories, most static hosts redirect /about to /about/. Google follows that redirect, so the default is harmless — but the canonical URL Vertex emits is the no-slash form, which means the canonical and the served URL differ by a redirect.
For a multi-page site that should advertise exactly the URLs it serves, opt into trailing slashes. Every non-root canonical, og:url, hreflang, breadcrumb, and sitemap entry then carries the slash. The default is off and byte-identical to the previous behavior.
{
"url": "https://example.com",
"trailingSlash": true
}The build spec
Pin the Node version to match local development. Vertex sites target Node 20.19 and npm 10.8 — installs on a newer npm produce lockfiles that resolve differently in CI, which surfaces as missing optional platform binaries during the build rather than as anything obviously version-related.
version: 1
frontend:
phases:
preBuild:
commands:
- nvm install 20.19.0 && nvm use 20.19.0
- npm install --prefer-offline --no-audit --no-fund
- npm run generate:public-assets
build:
commands:
- npm run build:ssg
artifacts:
baseDirectory: dist
files:
- '**/*'
cache:
paths:
- node_modules/**/*