Builder Guide
Host SaaS CSS, logos, images, and design assets
Upload app-scoped assets, organize virtual folders, publish validated CSS, and use stable public asset URLs in pages and React templates.
App Assets is the design-file library for one SaaS application. It stores logos, images, fonts, videos, PDFs, downloads, and a validated app stylesheet without putting file bytes or server paths in page JSON. Public files receive an immutable URL under that SaaS app's identity.
Uploads are private by default. Public delivery requires an explicit selection and should be used only when a browser or published stylesheet must load the asset without an authenticated content request.
Automate assets through the Developer API
A trusted developer backend has the same three styling layers as the dashboard: app-wide theme, shared assets, and page drafts/publishing. Use GET/PUT /v1/apps/{saasAppId}/theme with themes.read/themes.write for the theme, validated --runtime-* variables, and base design tokens. Use assets.read/assets.write for the asset routes. Page layout and page-level tokens use the existing page-draft, validation, history, and publish routes.
const api = new BuildWithHQConnector({{ saasAppId, credential }});
await api.uploadAsset({{
file: new Blob([css], {{ type: "text/css" }}),
fileName: "theme.css",
folderPath: "theme",
assetType: "stylesheet",
isPublic: true,
}});
The live app credential belongs only in a trusted server or secured automation host. Browser React should receive the resulting public asset URL, never the credential.
Compile Tailwind locally in the React project, then upload the production CSS. The API does not execute npm, Tailwind plugins, arbitrary JavaScript, or customer build scripts. A headless React host can use its own CSS or link the returned public stylesheet URL.
The API never accepts a database, server, storage root, storage key, tenant account, or connection string. The app boundary is derived from the credential, and the database principal has execute-only access to reviewed asset procedures with no table or DDL permissions.
Upload and organize an asset
- Sign in to the SaaS as an account owner and choose Assets in the application header.
- Select a file and optionally enter a virtual folder such as
brand/logos,theme/fonts, orproduct/screenshots. - Uploads start private. Select Public design asset only when a browser page or stylesheet must load the file directly.
- Choose Upload, then copy the URL shown on the asset card.
The folder is a virtual label inside the SaaS. Slashes are normalized to a stable relative path. It cannot select a drive, network share, server directory, or another SaaS app.
An explicitly public file uses:
https://assets.buildwithhq.com/{saasAppId}/{assetId}
The server assigns both GUIDs. Do not construct an asset URL from a database name, account ID, user ID, filename, or storage path.
Publish custom CSS for one SaaS
- Open Custom CSS in App Assets and paste UTF-8 CSS using the existing
--runtime-*tokens and narrowly scoped selectors. - Choose Preview CSS and review normal, loading, empty, error, dialog, desktop, tablet, and mobile states.
- Choose Publish CSS. The server validates it and saves a new immutable public
theme.cssunder the virtualthemefolder. - The runtime loads the newest public stylesheet once per signed-in SaaS identity; ordinary page navigation does not reload it.
A stylesheet url(...) may use a fragment, relative application path, or the same SaaS app's asset prefix. Use exact public URLs for fonts and background images.
Published CSS rejects imports, executable URLs, scriptable legacy expressions, embedded markup, and remote or cross-app asset URLs. CSS cannot create an API route, grant a permission, or replace a native module action.
Use assets in pages and React
- Use the public URL in a registered logo, image, download, poster, or bounded asset property.
- Pass the URL as data to repository-maintained React; page JSON must never become an arbitrary import path.
- Keep meaningful alternative text and responsive dimensions in the owning component.
Current template-pack members do not copy asset bytes or remap source-SaaS URLs into a newly installed SaaS. Asset-dependent marketplace templates are not self-contained until exact-version asset packaging and destination remapping are implemented.
File and delivery rules
| File | Accepted? | Public behavior |
|---|---|---|
| DLL, COM, EXE | No | Rejected before storage |
| Validated CSS | Yes | Rendered as text/css |
| PNG, JPEG, GIF, WebP, AVIF | Yes | Rendered inline |
| MP4, WebM, WOFF, WOFF2, PDF | Yes | Rendered inline |
| HTML, SVG, scripts, archives, source, or unknown | Yes | Downloaded as an inert binary attachment with nosniff and sandbox policy |
Uploads retain the 25 MiB limit; CSS is limited to 512 KiB. Stored bytes are SHA-256 hashed. Removing an asset makes its URL unavailable rather than reusing its identity. Public delivery resolves the active app and retrieves only explicitly public metadata; the browser receives no storage key, path, database coordinate, or credential.
Troubleshooting
| Symptom | Check |
|---|---|
| Upload rejected | Check the extension, simple filename, virtual-folder traversal, and 25 MiB limit. |
| CSS rejected | Remove imports, executable or remote URLs, embedded markup, and unsupported encoding; remain below 512 KiB. |
| Public URL returns 404 | Confirm the asset is public, active, not removed, and belongs to the URL's SaaS app. |
| Asset host cannot connect | Have the operator verify DNS, TLS, reverse proxy, and preserved Host routing. |
| New CSS is absent | Confirm publish succeeded, reload once, and inspect link#bwhq-published-theme-css. |
Operators should continue with Deploy the SaaS asset domain and storage root. Template maintainers should also read Apply a TailAdmin-style design.
Compare all six styling approaches in Support for React.
Capability review: 2026-09-14. For exact current technical availability, use the generated API Map and first-class module inventory.