Websites
Forte builds front-end apps from a GitHub repository and serves them over HTTPS on a global content delivery network. Use websites for marketing pages, dashboards, single-page apps, documentation sites, and other static or server-rendered front ends.
Websites are front-end only. When you need user-authentication enforcement, the server-side Forte API (forte.projects.*, which requires FORTE_API_TOKEN), or request observability, pair your website with a Service and call it from the browser — see Authentication and request handling below.
Supported frameworks and hosting
Forte auto-detects and builds most popular frameworks — Next.js, Vite, Astro, Create React App, Vue, Angular, SvelteKit, Nuxt, plain HTML, and more. Based on your framework, Forte hosts your site in one of two ways:
- Static hosting — for sites that build to static files, Forte serves the output directly from a global CDN.
- Server-rendered (SSR) hosting — for frameworks that render on each request, Forte runs your server across regions worldwide.
Either way, your site is served over a global CDN with HTTPS, and Forte applies CDN caching following standard cache-control conventions (see Caching and revalidation).
How websites work
When you create a website, Forte connects to your GitHub repository, builds it, and serves the output globally over a CDN. Each git push to the configured branch triggers a new build and deployment automatically.
Website URL
Every website is assigned a unique HTTPS URL on the sites.tryforte.dev domain:
https://{websiteId}.sites.tryforte.devThis URL is permanent — Forte generates it when you create the website, and it never changes for the lifetime of the website, even across redeployments. You can copy it directly into DNS records, marketing materials, or any place that expects a stable URL.
Custom domains
Add a custom domain from the website's page in the Forte Console, then point your DNS at the domains.tryforte.dev endpoint shown there (a CNAME). Forte provisions and renews TLS certificates automatically. Your generated sites.tryforte.dev URL keeps working alongside your custom domain.
Build configuration
Forte detects how to build most frameworks (Next.js, Vite, Astro, Create React App, Vue, Angular, plain HTML, and more). When auto-detection isn't enough, you can override:
| Setting | Description |
|---|---|
| Build command | The command Forte runs to build your website (for example, npm run build) |
| Output directory | The folder where built files land (for example, dist, out, build) |
| Install command | The command to install dependencies (for example, npm install) |
| Package manager | One of npm, yarn, pnpm, or bun |
| Node.js version | The major version of Node.js used to build (for example, 18, 20) |
| Subdirectory | The path within your repository to build from — used for monorepos |
If your repository changes — say, you add a new framework or move where package.json lives — you can reset the auto-detected configuration on the website's edit page so Forte detects fresh on the next build.
Build triggers
Choose how new deployments are triggered:
- On every push to branch — Every commit to the configured branch redeploys automatically. Best for staging and continuous-deployment workflows.
- On GitHub release published — Only redeploys when a new GitHub release is published. Best for production websites that should only roll forward on tagged releases.
You can also manually deploy any commit at any time from the website's deployment page.
Environment variables and secrets
Set environment variables and secrets on your website:
- Environment variables are injected into the build environment and accessible through standard mechanisms like
process.env.NAMEin Node.js. They're visible in the console and in build logs. Use them for non-sensitive build-time configuration like feature flags and public API URLs. - Secrets are encrypted at rest and never displayed in the console once saved. Forte injects them where the website type actually has somewhere to read them: into the build environment (also
process.env.NAME) for static websites, since a static site has no runtime to inject into afterward; into the runtime environment for server-rendered (SSR) websites, the same way as for Services. Secret values are never written to build logs or echoed anywhere Forte logs output.
Naming a secret with a framework's public prefix (NEXT_PUBLIC_, VITE_, etc.) still adds it to the client-visible bundle. Secrets hide a value from the Forte console and build logs, but your framework can still expose it. Don't use a public prefix for values that must stay server-side.
The FORTE_ and AWS_ prefixes are reserved — you cannot create custom environment variables that start with either. A handful of other names are also reserved for the automatic identifiers described below.
Automatic identifiers
Forte injects the website's project ID and website ID into every build and, for server-rendered sites, into the runtime. Each identifier is exposed under every common framework prefix so it reaches both your server code and your client bundle without extra configuration:
| Identifier | Canonical | Next.js | Vite | CRA | Angular | SvelteKit | Nuxt |
|---|---|---|---|---|---|---|---|
| Project ID | FORTE_PROJECT_ID | NEXT_PUBLIC_FORTE_PROJECT_ID | VITE_FORTE_PROJECT_ID | REACT_APP_FORTE_PROJECT_ID | NG_APP_FORTE_PROJECT_ID | PUBLIC_FORTE_PROJECT_ID | NUXT_PUBLIC_FORTE_PROJECT_ID |
| Website ID | FORTE_WEB_APP_ID | NEXT_PUBLIC_FORTE_WEB_APP_ID | VITE_FORTE_WEB_APP_ID | REACT_APP_FORTE_WEB_APP_ID | NG_APP_FORTE_WEB_APP_ID | PUBLIC_FORTE_WEB_APP_ID | NUXT_PUBLIC_FORTE_WEB_APP_ID |
All these names are reserved — attempting to set one of them as a custom env var or secret is rejected with a validation error so the platform value is always the one your code reads.
FORTE_API_TOKEN is not injected into websites. A token in client code would let every visitor act as the project owner. To use the Forte API with project-level privileges, deploy that logic as a Service. The Service receives FORTE_API_TOKEN securely, and your website can call it. See API Surfaces for the full credential-safety model.
Authentication and request handling
Websites are public — every visitor can access them. Website requests are served directly from the CDN and do not pass through the Forte gateway. This holds for both static and server-rendered (SSR) websites: your SSR server code runs, but Forte does not sit in front of it.
The request-time features that Services get do not apply to websites — static or SSR:
- No user-authentication enforcement. Forte does not authenticate requests to a website or inject the
X-Forte-User-Idheader. Auth path exclusions and end-user session enforcement are Service features — an SSR website must build and enforce its own auth. - No per-request observability. The request logs, metrics, and latency percentiles described in Monitoring are captured for Services only. Forte does not log or meter individual requests to a website.
forte proxyand local auth testing are Service features.
If your front-end needs authenticated, observable request handling, deploy that logic as a Service. A Service receives the X-Forte-User-Id header and Forte session context automatically on every authenticated request, and each request is logged and metered. Your website can call that Service from the browser.
Caching and revalidation
Forte serves your website over a global CDN. This section covers what gets cached, how to control it, and the rules around revalidating server-rendered content.
Static assets
The fingerprinted build output a framework emits — hashed JavaScript, CSS, and media files — is cached aggressively. These files are immutable: when their content changes, their filename changes, so a new deploy is picked up right away without serving anything stale. You don't need to configure this.
Server-rendered responses
For a server-rendered (SSR) website, caching is driven by the Cache-Control header your app sets on each response:
- No
Cache-Control(orno-store) — the response is generated fresh on every request. This is the right default for dynamic, per-user pages. Cache-Controlwith a positive shared lifetime (for examples-maxage) — the response is cached at the CDN for that period and reused for every visitor, then refreshed.
Set these headers in your framework the same way you would behind any CDN.
Time-based revalidation
Time-based revalidation works. In Next.js, a route segment with:
export const revalidate = 60is served from cache for the configured number of seconds, then refreshed on the next request after it expires. This is honored at the CDN through the response's cache headers, so it behaves the same for every visitor. Use it for content that changes on a schedule — a blog index, a product listing, a homepage.
On-demand revalidation
On-demand revalidation — revalidateTag, revalidatePath, or the Pages Router res.revalidate — is not reliable on Forte.
Forte runs your app on more than one server. An on-demand revalidation call only refreshes the cache on the server that handles it; the other servers and the CDN are unaffected, so a page you expect to update may keep serving its previous version.
Use one of these instead:
- Time-based revalidation (
export const revalidate) for content that changes. - Redeploy to publish updated content immediately — a deploy refreshes everything.
If your build calls an on-demand revalidation API, Forte adds a note to your build log pointing back to this page.
Server-rendered request limits
Server-rendered websites handle ordinary request/response web traffic. A few limits apply when you build one:
- No WebSockets or other long-lived connections. Use ordinary HTTP requests.
- Requests must finish within about a minute. Move long-running work — large reports, media processing — to a background job instead of doing it inside a request.
- Keep request bodies small. Large uploads (multi-megabyte files) should go straight to your storage provider, with your app handling only a reference to the file.
Reading the visitor's domain
Forte sits in front of your app, so the standard Host header your code sees is an internal value. To get the domain the visitor actually used — for canonical URLs, redirects, metadata, or sitemaps — read the x-forwarded-host header. Most frameworks already do this for you.
If you use an authentication library, turn on its trust-host option so it builds callback URLs from the forwarded host. In Auth.js / NextAuth, set:
trustHost: true