Swell App frontends can serve different purposes, depending on the goal of the app. A frontend is essentially its own application within a Swell App, intended to render pages for public display. For example, a storefront app implements the page structure and functionality of a storefront using a frontend. Frontends run as Cloudflare Workers, either hosted by Swell or deployed to your own Cloudflare account.

You can create a new frontend with the following CLI command. It prompts for a frontend template, and sets frontend.hosting in swell.json to the template's hosting mode. You can also add a compatible framework to the app's frontend/ folder yourself.

swell create frontend

To skip the prompt, pass a template, for example swell create frontend --frontend swell-react -y. See Frameworks for the templates.

  • Storefront apps: Customer interfaces such as product pages, checkout, account portals, and more.
  • Admin apps: Merchant user interfaces that are embedded in the Swell dashboard.
  • Integrations: Configuration or other interstitial interfaces to support unique workflows, serving either merchants or customers.

Proxima app serves as an example for developers to learn best practices for developing storefront frontends, but the sky is the limit. With a wide range of framework choices, any number of storefront use cases can be achieved on the Swell platform. The React SPA Storefront template, swell-spa, starts a new storefront app on managed hosting.

A frontend can be embedded in Swell's dashboard, to provide a more flexible interface for merchants to manage data and settings for your app. Links with the frontend:// scheme in content views, navigation and actions open the app's frontend inside the dashboard. A store user who opens it this way is identified by the admin claim of Swell-Context. See Swell API access.

A frontend is either managed, hosted by Swell, or self-hosted in your own Cloudflare account. Set the mode with frontend.hosting in swell.json. When it isn't set, the frontend is self-hosted.

  • managed: Swell deploys the frontend on its own Cloudflare account, so you don't need one. Managed frontends support Vinext, and client-side React with Vite.
  • self-hosted: the CLI deploys the frontend with Wrangler to your own Cloudflare account. Self-hosted frontends support Next.js with OpenNext, Astro, Nuxt, React with Vite, Hono and Angular.

Next.js apps must be self-hosted. To move a managed frontend to self-hosted, set frontend.hosting to self-hosted. Removing the key isn't enough.

swell create app and swell create frontend accept the following templates with --frontend. The managed templates require Node.js 22.22.2 or later.

TemplateFrameworkHosting
swell-reactReact and Vite, with client rendering and server endpointsmanaged
swell-vinextVinext, with server renderingmanaged
swell-spaReact SPA Storefront, for storefront appsmanaged
nextjsNext.jsself-hosted
astroAstroself-hosted
nuxtNuxtself-hosted
reactReact and Viteself-hosted
honoHonoself-hosted
angularAngularself-hosted

We will expand this list as demand for additional support grows. If your framework of choice is not yet supported, reach out to us or make a pull-request on Github.

To simplify your frontend's interactions with the Swell platform, we've developed the Apps SDK, a Typescript-based library that comes built-in with frontend and backend API clients, and theme rendering logic for storefront apps.

→ See the Apps SDK reference for more details.

During local development, you'll be able to run the app on your machine and quickly preview changes using the following CLI command:

swell app dev

This will perform several functions:

  • Start a local proxy through a Cloudflare tunnel.
  • Start the app using its own dev command, for example next dev or astro dev.
  • Add the local proxy URL to your account session, which informs Swell that your app dev server is running and should be loaded instead of a deployed version.
  • Note: This command will also start a development server for app functions, if any exist.

You should only run app dev on one app at a time, otherwise your account session will only remember the last app that was started.

When the command is successfully executed, it prints a URL to preview the app through the proxy. It also watches for changes and automatically pushes configurations and files to Swell as you develop the app. The preview always uses your local dev server, for both managed and self-hosted frontends.

When you're ready to test your frontend in the cloud, or to make a final deployment before release, deploy it with the CLI. How the CLI deploys depends on frontend.hosting:

  • Managed: the CLI builds the frontend with vinext build or vite build, packages the Worker and its static assets, and uploads the package to Swell, which deploys it. The CLI rebuilds the frontend on every deploy.
  • Self-hosted: the CLI runs the framework's build command and deploys the frontend with Wrangler to your own Cloudflare account. It skips the deploy when the frontend hasn't changed, unless you pass --force.

For a self-hosted frontend, first log in to Cloudflare using wrangler:

wrangler login

In a non-interactive shell, also export CLOUDFLARE_ACCOUNT_ID. Then deploy the frontend, in either hosting mode, with the following command:

swell app frontend deploy

swell app push also deploys the frontend after pushing the app's configuration, and so does pushing a path inside frontend/. Pass --no-deploy to skip it.

Admin and integration app frontends are served at https://<store-id>--<installation-id>--app.swell.store, and storefront app frontends on the store's storefront domains. swell app push and swell app frontend deploy update the app in the store's test environment. A released app version keeps the frontend it was released with.

Swell handles some paths on an app's domain before they reach the frontend, including /api, /graphql, /functions and /.well-known. On storefronts, /checkout goes to Swell's hosted checkout unless the store uses a custom checkout. Serve your app's own endpoints under /app-api, which Swell passes to the frontend with the path, query and body unchanged.

  • Only the ASSETS binding is available. KV, D1, R2, Durable Objects, queues, service bindings, environment variables and secrets aren't. Use app settings for configuration.
  • The compatibility date is fixed at 2026-09-08, with no compatibility flags. Node.js built-in modules are available at this date.
  • npm dependencies must be bundled into the Worker. The CLI reports any that aren't.
  • A package can contain up to 5,000 files, with a total size of up to 5 MiB.
  • Swell doesn't cache responses on a CDN. Browsers cache responses that set Cache-Control with max-age and immutable.
  • Worker logs aren't available in swell logs. Use your local dev server's logs and the deployment errors to diagnose issues.

Managed deployments return errors with the following codes. A failed deployment leaves the previous frontend serving.

CodeMeaning
frontend_package_invalidThe package failed validation. The message gives the reason.
frontend_deployment_failedCloudflare rejected the upload. Correct the reported error and deploy again.
frontend_package_inactiveA version was created while the selected package wasn't the active deployment. Deploy the package first.
frontend_url_check_failedThe URL of a self-hosted frontend failed its check when switching from managed hosting. The managed frontend stays active.
frontend_deployment_busyAnother operation is updating the app. Try again shortly.
frontend_deployment_changedThe deployment changed during the operation. Deploy again.
frontend_selection_changedThe app's frontend selection changed during the operation. Try again.
frontend_activation_failedThe app update couldn't be completed. Try again shortly.

When your app is invoked, either as a storefront or as an admin app, Swell will proxy the request along with headers that can be used by the app to identify the merchant and authenticate with the store's frontend and backend APIs.

The following table outlines the headers passed to a frontend app when requested:

HeaderDescription
Swell-ContextSigned JSON Web Token identifying the store, app, installation and store user for the request. See Verifying requests.
Swell-Store-IdID of the store.
Swell-Environment-IdString 'test' indicates the request is from a test environment, while blank indicates a live environment.
Swell-App-IdID of the app, as set by `id` in swell.json.
Swell-App-VersionVersion of the app, i.e. "1.0.0". Not sent for apps in development.
Swell-App-RouteSet to `/` when the request path started with the app's private ID. Swell removes that prefix before forwarding the request.
Swell-Access-TokenUnique backend API key representing scoped access for the app installed in a merchant's store. Keep it on the server.
Swell-Public-KeyUnique frontend API key representing scoped access for the app installed in a merchant's store.
Swell-API-HostURL of the backend API, such as `https://api.swell.store`.
Swell-Admin-UrlBase URL of the store, such as `https://.swell.store`.

Storefront-specific headers:

HeaderDescription
Swell-Storefront-IdID of a storefront using this app, if applicable.
Swell-Deployment-ModeIndicates the storefront context for the request. One of `editor`, `preview`, or `live`.
Swell-Cache-ModifiedDate the storefront was last modified or published, relative to this request.
Swell-Storefront-HostDomain of the request, without `www.` or the port.
Swell-Storefront-ContextURL-encoded JSON with the visitor's `account` and `cart`, when it fits in the request headers.

Theme-specific headers:

HeaderDescription
Swell-Theme-IdID of a theme that should be loaded by this app.
Swell-Theme-VersionVersion of the theme, i.e. "1.0.0".
Swell-Theme-Version-HashUnique hash of all theme files combined, often used to cache response output in association with other properties.
Swell-Theme-Config-VersionVersion of the theme configuration: `preview-` for previews, or `live-` for the published configuration.

These headers are unique for each store and its app installation. Once invoked, your frontend will likely connect to the Swell Frontend API, Backend API, or both, using the access token (backend) and public key (frontend) provided via headers. Keep the access token on the server, and send only the public key to the browser.

Example

Using the Apps SDK:

Apps SDK
import { Swell } from '@swell/apps-sdk';

const swell = new Swell({
  serverHeaders: context.request.headers, // Object received from worker environment
  ...options,
});

// Make a backend API call
await swell.backend.get('/products');

// Make a frontend API call
await swell.storefront.get('/products');

Using Swell libraries:

Swell libraries
import Swell from 'swell-node';
import SwellJS from 'swell-js';

const storeId = context.request.headers['Swell-Store-Id'];
const accessToken = context.request.headers['Swell-Access-Token'];
const publicKey = context.request.headers['Swell-Public-Key'];

// Initialize backend API client
const backend = Swell.init(storeId, accessToken, [...options]);

// Initialize frontend API client
const storefront = SwellJS.create(storeId, publicKey, [...options]);

You may otherwise prefer to build your own request handlers using the Fetch API, following our backend and frontend API guides for details.

Swell-Context is a JSON Web Token signed by Swell with ES256, and expires 60 seconds after it's issued. Only trust the store, app or store user it identifies after verifying it. The other Swell-* headers aren't signed.

Verify the signature with the key from https://swell.store/.well-known/jwks.json that matches the token's kid. Then check that iss is https://swell.store, aud is your app's ID, and the token hasn't expired. The token contains:

  • store_id, environment_id (test, or null for live), app_id, installation_id and storefront_id
  • api_host and admin_url
  • admin: { "user_id": "<id>" } when a store user opened the frontend from the dashboard, otherwise null

Use the admin claim to identify the store user, rather than the _swell_admin_session cookie, which is temporary.

Because frontends are hosted by Cloudflare Workers, your app has access to standard worker context properties and runtimes. Managed frontends have the limits listed under Managed frontends.

Here are some useful docs to better understand the worker environment:

For self-hosted frontends, Cloudflare KV is recommended for caching output to optimize app performance.

Things to consider:

  • The Cloudflare Worker environment supports a limited subset of the Node.js runtime. Some npm packages may rely on APIs that are unavailable in this context.
  • Some npm libraries may work on your local machine, however due to the difference in local vs Worker Node.js environments, it's important to test cloud deployments regularly.
  • When deploying a storefront app on your own Cloudflare account, it is your responsibility to maintain the account in order for the app to remain accessible to users.