Skip to content
View as Markdown

Static Website

Static Website is a service for hosting static web applications on the Tailor Platform.

Overview

Static Website provides:

  • Static file hosting
  • Type-safe URL references for configuration
  • IP address restrictions
  • Custom domain support

For the official Tailor Platform documentation, see Static Website Guide.

Configuration

Configure static website hosting using defineStaticWebSite():

Definition Rules:

  • Multiple websites allowed: You can define multiple static websites in your config file
  • Configuration location: Define in tailor.config.ts and add to the staticWebsites array
  • Uniqueness: Website names must be unique across all static websites
typescript
import { defineStaticWebSite, defineConfig } from "@tailor-platform/sdk";

const website = defineStaticWebSite("my-website", {
  description: "My Static Website",
});

// You can define multiple static websites
const adminWebsite = defineStaticWebSite("admin-website", {
  description: "Admin Dashboard",
});

export default defineConfig({
  staticWebsites: [website, adminWebsite], // Add all websites to the array
});

Options

description

A description of the static website:

typescript
defineStaticWebSite("my-website", {
  description: "Frontend application for my service",
});

allowedIpAddresses

Restrict access to specific IP addresses in CIDR format:

typescript
defineStaticWebSite("my-website", {
  allowedIpAddresses: ["192.168.0.0/24", "10.0.0.0/8"],
});

customDomains

Associate custom domains with the static website:

typescript
defineStaticWebSite("my-website", {
  customDomains: ["app.example.com"],
});

After deploying, use tailor staticwebsite domain get <domain> to check domain status and retrieve the CNAME targets required for DNS configuration.

A domain can be associated with only one workspace at a time. To set custom domains only in the workspace that owns the domain, see Multi-Environment Configuration.

Type-safe URL References

The returned website object provides a url property that resolves to the actual URL at deployment time. Use this for type-safe configuration:

CORS Settings

typescript
const website = defineStaticWebSite("my-frontend", {
  description: "Frontend application",
});

export default defineConfig({
  cors: [website.url], // Resolved at deployment
  staticWebsites: [website],
});

OAuth2 Redirect URIs

typescript
const website = defineStaticWebSite("my-frontend", {
  description: "Frontend application",
});

const auth = defineAuth("my-auth", {
  oauth2Clients: {
    "my-client": {
      redirectURIs: [
        `${website.url}/callback`, // https://my-frontend.example.com/callback
        `${website.url}/auth/complete`, // https://my-frontend.example.com/auth/complete
      ],
      grantTypes: ["authorization_code", "refresh_token"],
    },
  },
});

Application Environment Variables

typescript
const website = defineStaticWebSite("my-frontend", {
  description: "Frontend application",
});

export default defineConfig({
  env: {
    siteUrl: website.url, // https://my-frontend.example.com
  },
  staticWebsites: [website],
});

Resolver, executor, workflow job, and auth before-login hook code, and TailorDB migration scripts, that read env receive the deployed URL, even when the same deploy both creates the website and reads its URL — one deploy call resolves it, with no second, manually-triggered deploy needed. If the referenced website does not exist at all, the CLI warns and leaves the unresolved reference in place. If the reference still can't be resolved after this deploy's rebuild, the deploy fails instead of shipping the unresolved reference. This platform lookup only happens during deploy; function run passes the literal <name>:url string unchanged, since it never talks to the platform to resolve it.

Complete Example

typescript
import { defineConfig, defineAuth, defineIdp, defineStaticWebSite } from "@tailor-platform/sdk";
import { user } from "./tailordb/user";

const website = defineStaticWebSite("my-frontend", {
  description: "Frontend application",
});

const idp = defineIdp("my-idp", {
  clients: ["default-client"],
  permission: {
    create: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
    read: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
    update: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
    delete: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
    sendPasswordResetEmail: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
  },
});

const auth = defineAuth("my-auth", {
  userProfile: {
    type: user,
    usernameField: "email",
    attributes: { role: true },
  },
  oauth2Clients: {
    "frontend-client": {
      redirectURIs: [`${website.url}/callback`],
      grantTypes: ["authorization_code", "refresh_token"],
    },
  },
  idProvider: idp.provider("default", "default-client"),
});

export default defineConfig({
  name: "my-app",
  cors: [website.url],
  idp: [idp],
  auth,
  staticWebsites: [website],
});