Websites & Static Hosting

Deploying front-end apps, caching, and website build triggers.

Common questions

How do I host a static site or frontend on Forte?

Create a website in your project: pick the GitHub repository and branch, and Forte detects the framework, builds it, and serves the output over HTTPS on a global CDN. Every push (or release, depending on your trigger) redeploys automatically.

The URL is permanent for the lifetime of the website, and each project includes up to 10 websites free.

Read the documentation

What's the difference between a website and a service?

A website is your front end — built from GitHub and served as static or server-rendered pages from a global CDN, publicly accessible. A service is your back end — a containerized app behind Forte's gateway, which enforces user authentication and records per-request logs and metrics.

Websites bypass the gateway entirely, even server-rendered ones, so anything that needs auth enforcement or request observability belongs in a service your website calls from the browser.

Read the documentation

Which frontend frameworks does Forte auto-detect?

Next.js, Vite, Astro, Create React App, Vue, Angular, and plain HTML are recognized out of the box, among others. When auto-detection isn't enough, you can override the build command, output directory, install command, package manager, and Node.js version — and reset back to auto-detection later if your repository changes.

Read the documentation

How do I roll back a website to a previous deployment?

On the website's page, click "Deploy a different commit/release…" and pick the commit or release you want, or click Retry Deployment on any past build to rebuild it as-is. From the CLI, run "forte websites deploy" with the --commit flag.

Read the documentation

How does caching work for my website?

Fingerprinted build output — hashed JavaScript, CSS, and media — is cached aggressively and safely, because filenames change whenever content does. Server-rendered pages follow the Cache-Control header your app sets: no header means every request renders fresh, while a shared lifetime like s-maxage caches the response at the CDN for every visitor. Time-based revalidation (Next.js "export const revalidate") is honored.

Read the documentation

Why isn't revalidateTag or revalidatePath updating my page?

On-demand revalidation isn't reliable on Forte: your app runs on multiple servers, and a revalidation call only refreshes the server that handled it — the others and the CDN keep serving the previous version.

Use time-based revalidation ("export const revalidate") for content that changes on a schedule, or redeploy to refresh everything immediately.

Read the documentation

How do I deploy my website only on tagged releases instead of every push?

Set the website's build trigger to "On GitHub release published". Forte then redeploys only when you publish a release — a good fit for production sites that should roll forward deliberately, while staging sites keep the on-every-push trigger. You can still manually deploy any commit at any time.

Read the documentation

Why is FORTE_API_TOKEN missing from my website?

It's left out deliberately. A website ships its code to every visitor's browser, so a token reachable from client code would let any visitor act as the project owner.

If a server-rendered site needs project-level API access, store the token as a Secret on the website and read it only in server-side code paths — or better, put that logic in a service.

Read the documentation

How do I read the visitor's domain in my server-rendered site?

Read the x-forwarded-host header instead of Host — Forte sits in front of your app, so Host carries an internal value. Most frameworks handle this automatically; if you use an auth library like Auth.js/NextAuth, enable its trust-host option (trustHost: true) so callback URLs are built from the forwarded host.

Read the documentation

What are the limits for server-rendered websites?

Server-rendered sites handle ordinary request/response traffic: no WebSockets or other long-lived connections, requests should finish within about a minute, and large uploads should go straight to your storage provider rather than through a request body. Move long-running work — big reports, media processing — into a background job instead of a request.

Read the documentation