Deployment & Launch
Margo builds a static site into dist/, so it runs on any static host. It ships ready-made settings for Netlify (netlify.toml), Vercel (vercel.json, vercel.sh), and Cloudflare Pages (wrangler.toml). The site needs no account or environment variables.
| Setting | Value |
|---|---|
| Build command | npm run build |
| Output directory | dist |
| Node.js version | 22.23.4 or later |
| Package manager | npm (package-lock.json) |
Before You Launch
Go through this list once. Each item links to the page that explains it.
Address and identity
-
[site] baseUrlis your real address, not the shippedhttps://example.complaceholder, andnpm run buildshows no[site]warning (SEO & AI Visibility) -
title,tagline,description, andlogoTextin[site], andauthorandkeywordsin[seo], describe you or your studio. The tagline is added to every page title. French and Arabic have their ownsite.taglineandsite.descriptioninsrc/i18n/fr.jsonandsrc/i18n/ar.json(Config Reference) -
[seo.identity]says whether the site belongs to aPersonor anOrganization, with your name and, for a person, your job title - The logo, favicons (
npm run generate-favicons), social image (npm run generate-og-image, after the two items above), colors intheme.css, and fonts infonts.jsonare yours (Site Identity & Logo, Colors & Fonts)
Contact and forms
-
contactFormActionandcontactFormProviderpost to your own account (Formsubmit, Formspree, or Netlify Forms), and the build prints no[forms]warning (Forms) - The Mailchimp
formActionunder[settings.subscription]is your list, orenable = falsethere if you don’t send a newsletter -
emailandbookingunder[settings.contactInfo]are yours.bookingis where every Book a call button goes (Contact & Booking) - The contact rows in
src/content/sections/<language>/contact-section.md, and the email and phone infooter.mdandcall-to-action.md, are yours (Footer) - A project-wide search for
example.comand555finds nothing you still need to change
Sample content
- The sample projects and photo series in
src/content/projects/are replaced with your own work, and the herocardson the homepage point to them (Projects) - The services, journal posts and authors, team members, testimonials, and client logos are yours or removed (Collections)
- Every price and question on the pricing and FAQ pages is yours (Pricing & FAQ)
- Every sample photo is replaced (Icons & Images)
Pages and menus
- The privacy policy, terms, and cookie policy in every language folder of
src/content/pages/(privacy-policy.mdx,terms-conditions.mdx,cookie-policy.mdx) are rewritten for your practice and reviewed. They ship as sample text with a notice at the top - The Pages demo menu is hidden (
"enable": falsein every menu file), and the menus point at your pages (Menus) - The demo homepages you don’t use are deleted (Homepages), and
/elements/and/components/are removed if you don’t want the layout and shortcode galleries online (Pages) -
[settings.layoutSwitcher] enable = false, and thePUBLIC_DEMO_MODEenvironment variable is not set on your host -
footer.copyrightinsrc/i18n/<language>.jsonreads the way you want, and the links insrc/config/social.jsonare yours
Analytics and checks
- Analytics tags are in
[head], marked withdata-consentwhile the cookie banner is on (Cookies & Analytics) -
npm run astro-checkandnpm run buildfinish without errors, and you have looked at every page whose section files you changed (astro-checkdoesn’t check section files or the contact, FAQ, and pricing page files) - The Arabic text has been reviewed by a native speaker, if you keep Arabic
- You checked the site at phone width, in dark mode, and in every language you keep
Deploy
- Push your project to GitHub, GitLab, or Bitbucket.
- In Netlify, choose Add new site → Import an existing project and pick the repository.
- Netlify reads
netlify.toml: build commandnpm run build, publish folderdist, Node.js 22. Click Deploy.
The build uses baseUrl from config.toml unless you add a SITE_URL environment variable in the Netlify site settings.
netlify.toml also sets long-term caching for /_astro/* and /images/*, and sends missing /fr/... and /ar/... URLs to that language’s 404 page. When you add a language, add its own block, as the comment in the file says.
Using Netlify Forms? Set contactFormProvider = "netlify" and contactFormAction = "/", enable form detection under Forms in the Netlify dashboard, and redeploy.
- Push your project to GitHub, GitLab, or Bitbucket.
- In Vercel, choose Add New → Project and import the repository. Framework preset: Astro.
- Vercel reads
vercel.json, which builds withsh vercel.sh. Click Deploy.
vercel.sh sets the site address (SITE_URL) for each build, and on Vercel it replaces baseUrl:
- Production builds use the
SITE_URLenvironment variable if you set one in the Vercel project settings. Otherwise they use your Vercel production domain. SetSITE_URL(for examplehttps://www.your-domain.com) when you want one exact address, such as thewwwor the bare domain. - Preview builds use
https://staging.<your production domain>.
Edit vercel.sh if you want something else.
vercel.json also turns on trailing slashes, redirects /sitemap.xml to /sitemap-index.xml, and serves the .md copies (marked noindex) and the llms files as text.
From git: in the Cloudflare dashboard, open Workers & Pages → Create → Pages → Connect to Git, pick the repository, and set the build command to npm run build and the output directory to dist (the same folder as pages_build_output_dir in wrangler.toml).
The included wrangler.toml sets NODE_VERSION = "22.13.1" under [vars], which is older than the 22.23.4 that Margo needs. Change it to "22.23.4" or a later version of Node 22 before your first deploy. Cloudflare treats this file as the source of truth for the settings in it and shows them read-only in the dashboard, so change them in the file. Set your address with baseUrl in config.toml.
From your computer: Margo doesn’t install Wrangler (Cloudflare’s command-line tool) for you. Add it once, change name in wrangler.toml (shipped as margo-astro) to your project name, then log in, build, and deploy:
npm install -D wranglernpx wrangler loginnpm run buildnpm run deploy:cfRun npm run build and upload the contents of dist/ to your web server or static host (GitHub Pages, S3, a shared host, and so on). The included public/.htaccess covers Apache.
Ask your host how to serve .md files as text/markdown and llms.txt as text/plain, if you keep [seo.ai] markdownPages and llmsTxt on. Without that, some browsers download those files instead of showing them.
After You Launch
- Open the live site and click through the main pages, on a computer and on a phone, including the mobile menu, a project page, and dark mode.
- Send a test message through the contact form, and sign up to the newsletter if you use it, and check that both arrive.
- Open the search with ⌘ + K (Ctrl + K on Windows) and search for one of your projects.
- Click a Book a call button and check that it opens your scheduling page.
- Submit
https://your-domain/sitemap-index.xmlin Google Search Console and Bing Webmaster Tools. - Check the homepage and a project page with Google’s Rich Results Test.
- Share a link in a chat app to check the preview image.
Tell Search Engines About Changes With IndexNow
IndexNow tells Bing, Yandex, Seznam, and Naver which pages changed, so they visit them sooner. Bing also feeds ChatGPT search and Copilot. It is off until you set a key:
-
In
config.toml, setindexNowKeyunder[seo.ai]to a key of 8 to 128 letters, numbers, or dashes that you make up:[seo.ai]indexNowKey = "a1b2c3d4-your-own-key" -
Build and deploy. The build publishes the key file at
https://your-domain/<key>.txt, which the search engines check. -
After each deploy is live, run from your computer:
Terminal window npm run build # indexnow reads the sitemap in dist/npm run indexnow # pages changed in the last 7 daysnpm run indexnow -- --all # every page: use it after your first launchnpm run indexnow -- --days=30sends the pages changed in the last 30 days, andnpm run indexnow -- --dry-runlists the pages without sending them.
Updating The Live Site
With a git-connected host, every push to your main branch deploys automatically. Build locally first (npm run build) to catch errors before they reach your visitors.