Deploy to Cloudflare
Put the site online on Cloudflare, static or on demand, build on your computer or from GitHub, set the secrets and the domain, and keep the site up to date with Shopify's webhooks.
Smootify sites run on Cloudflare, as a Worker. This page puts the site online, adds your domain, and covers how a change in the store reaches the site.
Note
You need a Cloudflare account and a project with the @astrojs/cloudflare adapter, which Smootify Studio’s project has: see Create the project with Smootify Studio. Studio’s Deploy tab does the steps on this page for you, with Claude and your Cloudflare sign-in. The page says what happens, so you can do it by hand.
1. Static or on demand
- Static. Every page is a file made at build time. Nothing runs when a visitor opens a page, so it is the fastest and the cheapest. A change in the store shows after the next build.
- On demand. The product, collection and vendor pages are rendered when asked, and cached with tags. The home and 404 pages are still made ahead. Pages read the live collections: see Content from Shopify.
The only difference in astro.config.mjs is the cache provider of the on-demand mode:
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import { cacheCloudflare } from "@astrojs/cloudflare/cache";
export default defineConfig({
output: "static",
adapter: cloudflare(),
cache: { provider: cacheCloudflare() },
});2. Put the site online
Choose how the site is built:
- Build on your computer and upload. Run
pnpm build, then upload the result withwrangler. It saves Cloudflare build minutes. - Cloudflare builds from GitHub. Connect the project’s repository to the Worker in Cloudflare (Workers Builds). Each push to the branch starts a build. The project has
wrangleras a dependency, because the build runs it from a clean install.
The first deploy gives the site an address on *.workers.dev. It works on the Free plan.
To sign in to Cloudflare, run pnpm exec wrangler login (npx wrangler login with npm).
3. Add your domain
- In Cloudflare, add your domain to the Worker.
- In the Smootify dashboard, set the same domain as the site’s domain, and set
siteinastro.config.mjsto it. - Make sure the site has the plan the domain needs: a registered domain needs Lite, and server add-ons need Server. Free works only on
localhostand*.workers.dev.
4. Keep the site up to date
When a product, a collection or a page changes in Shopify, the site can follow without you. Shopify calls your site directly at /_smootify/webhook/<token>/, and the Smootify server only registers the webhooks. The route then does one of two things:
- On demand: it invalidates the cache of the pages that the change touches, by tag. A product change refreshes that product’s page and the pages that list products.
- Static: it asks Cloudflare to build the site again, through a deploy hook. This needs Cloudflare to build from GitHub, because the deploy hook belongs to Workers Builds.
Events are merged: the events of one window, 60 seconds by default, become one build or one purge, so a bulk edit does not start a build for each product.
On a static site built from GitHub, a change in Shopify is online in about two minutes, with no step on your side: the webhook arrives at once, the 60 second window closes, Cloudflare builds the site and publishes the new version.
Turn the route on in the config:
smootify({ siteId, webhook: true }); // or webhook: { debounce: 30 } for a 30 second windowIt needs these pieces. Studio’s Deploy tab sets all of them:
- a worker entry that hands requests to Astro and exports the debouncer, and its binding in
wrangler.jsonc:
// src/worker.ts
import { handle } from "@astrojs/cloudflare/handler";
import { withSmootifyWebhook } from "@smootify/astro/cloudflare";
export { SmootifyWebhookDebouncer } from "@smootify/astro/cloudflare";
export default { fetch: withSmootifyWebhook(handle) };// wrangler.jsonc
{
"main": "./src/worker.ts",
"durable_objects": { "bindings": [{ "name": "SMOOTIFY_WEBHOOK_DEBOUNCER", "class_name": "SmootifyWebhookDebouncer" }] },
"migrations": [{ "tag": "smootify-v1", "new_sqlite_classes": ["SmootifyWebhookDebouncer"] }]
}"workers_dev": trueinwrangler.jsoncwhen it also sets a custom domain;wrangleramong the devDependencies, which Cloudflare’s deploy step uses;- two secrets on the Worker:
SMOOTIFY_WEBHOOK_TOKENis the token Smootify gives when it registers the webhooks. The token in the address must equal it. A wrong token gets a plain 404.SMOOTIFY_DEPLOY_HOOKis the deploy hook address from Cloudflare (Settings, Builds, Deploy Hooks). Static sites only.
- the tags on your pages, for an on-demand site. A live entry’s
cacheHinthas them. A page that lists products carriesproductListCacheTags().
Put a secret on the Worker with pnpm exec wrangler secret put <NAME>, or in .dev.vars for a local preview. Never commit a secret.
The debouncer is a SQLite Durable Object, available on Cloudflare’s Free plan. Without its binding the route works, but acts on every event, and smootify() warns at build time.
Invalidating the cache makes Astro render the page again, but a build collection still holds the data of the last build. For fresh data on an on-demand site, read the live collections.
On a static site every change in the store costs a Cloudflare build, counted in your build minutes. To build only on your own computer, use on-demand pages or update the site by hand.
Studio registers only the webhooks the project needs: products and collections always, blogs, articles, pages and metaobject types only when a loader reads them.
5. Forms and email
A form that Shopify and Smootify do not take, such as a contact form, has two ways:
- Smootify’s metaobject creator, when the data belongs in Shopify. No backend. It is a server add-on, so it needs the Server plan.
- An API route on the Worker that sends the email with Cloudflare Email Service. This needs Cloudflare’s Workers Paid plan, about 5 USD a month, and a sender address on a verified domain. Add a
send_emailbinding to the wrangler config and read it fromcloudflare:workers. Protect the route with a honeypot field or Cloudflare Turnstile.
The success and error messages of the form are elements with form-done and form-fail: see Write components.
Before you publish
Check these first
- Cloudflare cannot install
@smootify/astro. The dependency points to a path or a file on your computer instead of the version on npm. Set it to the npm version, such as^0.1.0, and install again with the project’s package manager, so the lockfile follows. - The deploy step fails.
wrangleris not in the project. Add it as a dev dependency with the project’s package manager. - The webhook route answers 404. The token in the address is not the one in
SMOOTIFY_WEBHOOK_TOKEN, or the secret is not on the Worker. - A static site does not rebuild. There is no
SMOOTIFY_DEPLOY_HOOK, or the site is not built from GitHub. The route answers 200 withok: falseand does nothing. - An on-demand page shows old data. It reads a build collection. Use
getLiveEntryand setcacheHint. - Pages look different after a deploy. If something minifies the HTML after the build, keep the comments that begin
<!--smootify. On Cloudflare, turn off Auto Minify for HTML. - Smootify does not load full features on your domain. The domain is not set in the Smootify dashboard, or the plan is Free: a registered domain needs Lite.