[Skip to content](#main-content)

[![Jx Suite](/favicon.svg)
Suite](/)Search⌘KESC

Jump to

[Install Jx Studio](/docs/start/install)[Build your first project](/docs/start/first-project)[Document format](/docs/framework/concepts/documents)[Formula catalog](/docs/framework/reference/formulas)

↵
select↑↓
navigateesc
close

[Studio](/studio)[Framework](/framework)[Templates](/templates)[Compare](/compare)[Docs](/docs/start/first-project)[GitHub](https://github.com/jxsuite/jx)[Download](/download)

✕

[Studio](/studio)[Framework](/framework)[Templates](/templates)[Compare](/compare)[Docs](/docs/start/first-project)[GitHub](https://github.com/jxsuite/jx)

Color scheme&#xA;

[Download](/download)

☰

Docs menu

Start here[Overview](/docs/start/)Get started[Install Jx Studio](/docs/start/install/)[Your first project](/docs/start/first-project/)[A tour of Jx Studio](/docs/start/studio-tour/)Tutorials[Tutorial: interactive component](/docs/start/first-component/)[Tutorial: blog with collections](/docs/start/first-collection/)[Video tutorials](/docs/start/videos/)Coming from another tool[Coming from WordPress](/docs/start/coming-from-wordpress/)[Coming from Webflow or Framer](/docs/start/coming-from-webflow/)[Coming from Wix or Squarespace](/docs/start/coming-from-wix/)[Coming from Lovable or Builder.io](/docs/start/coming-from-ai-builders/)Studio[Overview](/docs/studio/)[The desktop app](/docs/studio/desktop/)The workspace[Overview](/docs/studio/interface/)[Welcome screen](/docs/studio/interface/welcome-screen/)[Editors and views](/docs/studio/interface/modes/)[The canvas](/docs/studio/interface/canvas/)[Documents and panes](/docs/studio/interface/tabs/)[Quick Access](/docs/studio/interface/quick-access/)[Keyboard shortcuts](/docs/studio/interface/shortcuts/)[Preferences](/docs/studio/interface/preferences/)[Languages](/docs/studio/interface/languages/)[Problems and progress](/docs/studio/interface/problems-and-progress/)[Commands](/docs/studio/interface/commands/)Projects[Overview](/docs/studio/projects/)[Create a project](/docs/studio/projects/create/)[Pages, layouts, components](/docs/studio/projects/pages-layouts-components/)[The Content workspace](/docs/studio/projects/browse/)[Starter templates](/docs/studio/projects/starters/)[Media](/docs/studio/projects/media/)[Content types](/docs/studio/projects/content-types/)[Project settings](/docs/studio/projects/settings/)[Dependencies and imports](/docs/studio/projects/dependencies/)Edit mode[Overview](/docs/studio/editing/)[Writing and formatting](/docs/studio/editing/writing/)[Slash commands](/docs/studio/editing/slash-commands/)[Frontmatter and metadata](/docs/studio/editing/frontmatter/)[Grid mode](/docs/studio/editing/grid/)Design mode[Overview](/docs/studio/design/)[Outline](/docs/studio/design/layers/)[Insert](/docs/studio/design/elements/)[Content tab](/docs/studio/design/properties/)[Style inspector](/docs/studio/design/style-inspector/)[Breakpoints](/docs/studio/design/breakpoints/)[States and selectors](/docs/studio/design/states-and-selectors/)[Design tokens](/docs/studio/design/tokens/)[Project Styles](/docs/studio/design/stylebook/)[Working with components](/docs/studio/design/components/)[Repeaters](/docs/studio/design/repeaters/)Logic[Overview](/docs/studio/logic/)[Formulas and expressions](/docs/studio/logic/formulas/)[Formula workspace](/docs/studio/logic/formula-workspace/)[Statements](/docs/studio/logic/statements/)[Logic tab](/docs/studio/logic/events/)[Data](/docs/studio/logic/data/)[Data sources](/docs/studio/logic/data-sources/)[Code editing](/docs/studio/logic/code/)Databases[Overview](/docs/studio/data/)[Connections](/docs/studio/data/connections/)[Data tables](/docs/studio/data/tables/)[Data grid](/docs/studio/data/grid/)[Auth and secrets](/docs/studio/data/auth-and-secrets/)AI assistant[Overview](/docs/studio/ai/)[The AI assistant](/docs/studio/ai/chat/)[Document assistant](/docs/studio/ai/document-assistant/)Publish[Overview](/docs/studio/publish/)[Source control](/docs/studio/publish/source-control/)[GitHub](/docs/studio/publish/github/)[Cloudflare Pages](/docs/studio/publish/cloudflare/)[Other hosts](/docs/studio/publish/other-hosts/)[Redirects](/docs/studio/publish/redirects/)[Real-time collaboration](/docs/studio/publish/collaboration/)Framework[Overview](/docs/framework/)Concepts[Documents](/docs/framework/concepts/documents/)[Elements](/docs/framework/concepts/elements/)[Components](/docs/framework/concepts/components/)[Props and scope](/docs/framework/concepts/props-and-scope/)[State](/docs/framework/concepts/state/)[Reactivity](/docs/framework/concepts/reactivity/)[References](/docs/framework/concepts/references/)[Expressions](/docs/framework/concepts/expressions/)[Statements](/docs/framework/concepts/statements/)[Functions and sidecars](/docs/framework/concepts/functions/)[Styling](/docs/framework/concepts/styling/)[Color schemes](/docs/framework/concepts/color-schemes/)[Popovers and overlays](/docs/framework/concepts/overlays/)[Accessibility](/docs/framework/concepts/accessibility/)[Lists and iteration](/docs/framework/concepts/lists/)[Data prototypes](/docs/framework/concepts/data-prototypes/)[Timing](/docs/framework/concepts/timing/)[Dynamic switching](/docs/framework/concepts/switching/)[Security](/docs/framework/concepts/security/)Site architecture[Overview](/docs/framework/site/)[project.json](/docs/framework/site/project-json/)[Routing](/docs/framework/site/routing/)[Layouts](/docs/framework/site/layouts/)[Content collections](/docs/framework/site/content-collections/)[Jx Markdown](/docs/framework/site/jx-markdown/)[Obsidian vault as content](/docs/framework/site/obsidian-vault/)[Relationships](/docs/framework/site/relationships/)[SEO and metadata](/docs/framework/site/seo/)[Locales and languages](/docs/framework/site/i18n/)[Images](/docs/framework/site/images/)[Redirects](/docs/framework/site/redirects/)[Feeds](/docs/framework/site/feeds/)[Site search](/docs/framework/site/search/)[Build output and adapters](/docs/framework/site/deployment/)How compilation works[Overview](/docs/framework/build/)[The dev server](/docs/framework/build/dev-server/)[CLI commands](/docs/framework/build/cli/)Working with agents[Overview](/docs/framework/agents/)[Authoring rules for agents](/docs/framework/agents/authoring-rules/)[Machine-readable docs](/docs/framework/agents/machine-readable/)Reference[Overview](/docs/framework/reference/)[Formula catalog](/docs/framework/reference/formulas/)[Operator reference](/docs/framework/reference/operators/)Extending[Overview](/docs/extending/)Extensions[Extension anatomy](/docs/extending/extensions/anatomy/)[Schema composition](/docs/extending/extensions/schema-composition/)[Custom classes](/docs/extending/extensions/classes/)[Custom formats](/docs/extending/extensions/formats/)[Capability methods](/docs/extending/extensions/capabilities/)[Project sections](/docs/extending/extensions/project-sections/)[Server mounts](/docs/extending/extensions/server/)[Connectors](/docs/extending/extensions/connectors/)[Search indexes](/docs/extending/extensions/search/)[Security and secrets](/docs/extending/extensions/security/)[Tutorial: a TOML format](/docs/extending/extensions/tutorial-toml-format/)[Tutorial: a guestbook](/docs/extending/extensions/tutorial-guestbook/)[First-party extensions](/docs/extending/extensions/first-party/)Embedding[Overview](/docs/extending/embedding/)[Hosting the Studio assets](/docs/extending/embedding/hosting/)[Writing a platform adapter](/docs/extending/embedding/platform-adapter/)[The backend protocol](/docs/extending/embedding/backend-protocol/)[Dev server internals](/docs/extending/embedding/dev-server/)[Embedding the runtime in your app](/docs/extending/embedding/runtime-host/)[Writing assistant tools](/docs/extending/embedding/assistant-harness/)UI kit[The Jx UI kit](/docs/extending/ui-kit/)Reference[Protocol routes](/docs/extending/reference/studio-routes/)[Implementation status](/docs/extending/reference/implementation-status/)[Spec changelog](/docs/extending/reference/spec-changelog/)[Standards alignment](/docs/extending/reference/standards/)Contributing[Working in the monorepo](/docs/extending/contributing/monorepo/)[Contributing to these docs](/docs/extending/contributing/docs/)[AI assistant evals](/docs/extending/contributing/ai-evals/)

# Build output and adapters

`bunx jx build` turns a project into an ordinary folder of web files. The output is standard static HTML, CSS, and JS, deployable anywhere, and an optional adapter adds the platform-specific pieces for hosts that run a server.

Run it from the project root (or pass the root as an argument). `--verbose` prints per-route progress; `--no-clean` skips wiping the output directory first. The other CLI commands are covered in [the jx CLI](/docs/framework/build/cli).

## The dist/ contract

Everything lands in one directory:

```text
dist/
├── index.html                # One HTML file per route
├── about/index.html
├── blog/hello-world/index.html
├── 404.html                  # The not-found page, when pages/404.* exists
├── about/index.md            # A Markdown copy of each page, linked from its <head>
├── components/               # Compiled component JS + CSS sidecars
├── images/_optimized/        # Responsive image variants
├── sitemap.xml               # When url is set in project.json
├── robots.txt                # From public/, with a Sitemap: line appended
├── _redirects                # From the redirects map
├── _headers                  # Response headers (below)
├── .nojekyll                 # So GitHub Pages doesn't eat the _-prefixed files above
├── favicon.svg               # public/ is copied in verbatim
└── worker.js                 # Only with a server adapter (see below)
```

Pages only load JavaScript for components that actually need it, so a fully static component ships as pre-rendered HTML and CSS with no script. Files from `public/` are copied verbatim, and the `copy` map in `project.json` can place additional files at chosen output paths.

## Response headers

The build writes `dist/_headers` because cacheability is something only the build can decide. It chose the filenames, so it is the only party that knows which of them contain a content hash:

```text
/*
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  X-Frame-Options: SAMEORIGIN
  Cache-Control: public, max-age=0, must-revalidate

/images/_optimized/*
  Cache-Control: public, max-age=31536000, immutable
```

Only the optimized images are cached forever, because their filenames embed a hash of the source, so a changed image is a changed URL. **Your component JS and CSS are not**, deliberately: `components/site-header.js` keeps the same URL when you edit the component, so caching it forever would serve stale code to everyone who visited before the edit.

**Cloudflare Pages, Cloudflare Workers and Netlify** read this file. The `node` and `bun` adapters serve no static assets, so there it is a description of what the reverse proxy in front of them should send, and the build says so when you use one.

Warning

`_headers`
&#x20;is a Cloudflare/Netlify convention, not a web standard.&#x20;
**GitHub Pages and most other plain static hosts ignore it entirely**
&#x20;and serve their own&#x20;
`Cache-Control`
. On GitHub Pages that is ten minutes, applied to everything including the optimized images this file marks immutable for a year. The security headers are not sent either.

The build cannot see where your&#x20;
`dist/`
&#x20;is going, so it warns when it can: with no adapter and a&#x20;
`public/CNAME`
&#x20;(GitHub Pages' custom-domain marker), it tells you the file will be ignored. If you need these headers applied, deploy behind a host that reads them.

To add your own rules, or turn parts off:

```json&#x20;shiki
```

Your own `public/_headers` still works: it is appended below the generated block, verbatim, and a later rule wins, so anything you write there overrides what the build set.

Warning

HSTS is off by default on purpose.&#x20;
`Strict-Transport-Security`
&#x20;tells browsers to refuse plain HTTP for your domain for&#x20;
`maxAge`
&#x20;seconds, and they remember it, so a wrong value locks the domain to HTTPS long after you notice. Turn it on once your certificate setup is settled.

## Content-Security-Policy

Also off by default, and also on purpose. Turn it on with one line:

```json&#x20;shiki
```

The build then derives the policy from the pages it just produced:

```text
Content-Security-Policy: base-uri 'self'; default-src 'self'; font-src 'self'; form-action 'self';
  frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; object-src 'none';
  script-src 'self' 'sha256-…' 'sha256-…'; style-src 'self' 'unsafe-inline'
```

`script-src` is the strict part, and it costs you nothing: compiled Jx output contains no `eval` and no `new Function`, event handlers are attached as listeners rather than written as `onclick=` attributes, and the runtime is served from your own site. The only inline scripts on a page are the import map and the colour-scheme pre-paint script, both identical on every page, so two hashes cover the whole site.

If your pages load anything from another origin, such as an analytics script, Google Fonts or a YouTube embed, the build sees it in the finished HTML and adds that origin to the right directive. What it can't see is the second hop: a third-party script that loads *another* script at runtime. That's the case to check.

Tip

Start with&#x20;
`"csp": "report-only"`
. You get&#x20;
`Content-Security-Policy-Report-Only`
, the browser reports what it&#x20;
*would*
&#x20;have blocked in the console, and nothing on your site breaks while you look. Switch to&#x20;
`true`
&#x20;when the console is clean.

### style-src is not strict

`style-src` keeps `'unsafe-inline'`, and will until the style pipeline changes. Every page carries a generated `<style>` block whose content differs per page, and per-element `style=` attributes have no hash form in CSP at all. Half-measures are worse than none here: a hash and `'unsafe-inline'` in the same directive cancel each other out, so adding a few style hashes would leave your pages unstyled.

### Overriding a directive

```json&#x20;shiki
```

A string replaces a directive wholesale, so restate the defaults you still want, and `false` removes it. `reportUri` emits `report-to`, the deprecated-but-widely-implemented `report-uri`, and the `Reporting-Endpoints` header that the first of those needs to mean anything.

## Manifest and security.txt

Two files a site is usually expected to publish. Both are generated from `project.json`, and both step aside if you put your own copy in `public/`.

### manifest.webmanifest

Declare a `manifest` section and the build writes `dist/manifest.webmanifest`, adds `<link rel="manifest">` to every page, and adds `<meta name="theme-color">` if you set one:

```json&#x20;shiki
```

`name` falls back to your project name and `start_url` to `/`, so the shortest useful manifest is a `manifest` key with icons in it. There's no manifest at all unless you declare the section, because it's a claim that your site is meant to be installed and most aren't.

Tip

The 192px and 512px icons are what a browser wants before it will offer to install the site. Leave one out and the build warns; it still writes the manifest, which is useful on its own for the name and theme colour.

### .well-known/security.txt

```json&#x20;shiki
```

Written to `.well-known/security.txt` and nowhere else, because [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116) §3 makes that the canonical spot, and a second copy at the root is a second thing to forget.

Warning

`expires`
&#x20;is required, and a date in the past&#x20;
**fails the build**
. That's deliberate: an expired&#x20;
`security.txt`
&#x20;is worse than none at all, because it advertises a reporting channel while telling the reporter its information is stale. Pick a date you'll actually revisit.

Want a clearsigned file? Put it at `public/.well-known/security.txt` and the build keeps yours. Signing needs a private key, which the build has no business holding.

## Service worker

Also off by default, and this one for a sharper reason than the rest: a service worker is **sticky**. It survives your next deploy, keeps running against a site that has moved on, and the people it breaks are the ones who came back.

```json&#x20;shiki
```

That writes `dist/sw.js` and adds a small registration script to every page. What it does:

- **HTML is always network-first.** The cache is a fallback for a request that failed, never a substitute for one; otherwise a stale page outlives every attempt you make to fix it.
- **Only `/images/_optimized/*` is cache-first**, because it's the one output whose filename contains a hash of its own contents. A cached hit there can't be wrong. Your components and assets aren't cached first for the same reason they aren't marked `immutable`: editing one reuses its URL.
- **`offlineFallback` is served for a failed navigation.** If you forget to precache it, the build adds it and tells you, because a page that was never cached can't be served offline.

Warning

Every URL in&#x20;
`precache`
&#x20;must be a page or file this build actually produces, and the build fails if one isn't. That's not pedantry: the browser's&#x20;
`cache.addAll()`
&#x20;is all-or-nothing, so a single typo'd URL stops the worker from installing&#x20;
**at all**
, with no error anywhere you'd think to look. The symptom is "the service worker just doesn't do anything".

### Turning it off

```json&#x20;shiki
```

**Not by deleting the key.** This is the one setting where "remove the config" is the wrong move, and it's worth understanding why.

Once a visitor's browser registers a worker, it keeps running it. Removing `sw.js` from your deploy doesn't help: a 404 at that URL isn't an instruction to stop, it's just a failed update check. Every previous visitor stays on the old worker, serving whatever it cached, and you have no way to reach them.

So `"serviceWorker": false` writes a **tombstone** at the same URL: a worker whose only job is to unregister itself, delete its caches, and reload the tab onto your live site. The next time a returning visitor's browser checks for an update, they get it and they're free.

Leave `false` in place for as long as you think old visitors might come back. Deleting the key later stops emitting the tombstone.

## Build options

The `build` section of `project.json`:

| Property        | Default    | What it does                                                        |
| --------------- | ---------- | ------------------------------------------------------------------- |
| `outDir`        | `"./dist"` | Output directory                                                    |
| `trailingSlash` | `"always"` | URL shape: `"always"` or `"never"` (below)                          |
| `sitemap`       | `true`     | Set `false` to skip [sitemap generation](/docs/framework/site/seo)  |
| `adapter`       | *(none)*   | `"cloudflare-workers"`, `"cloudflare-pages"`, `"node"`, or `"bun"`  |
| `headers`       | *(on)*     | Response headers written to `_headers` (below)                      |
| `minify`        | `true`     | Minify emitted browser JavaScript; set `false` for readable bundles |

### trailingSlash

`"always"` (the default) writes every route as a directory index, so `/about` becomes `dist/about/index.html`, so the canonical served URL is `/about/`. `"never"` writes flat files, `dist/about.html`, for hosts that serve extensionless or `.html` URLs. Pick whichever matches how your host serves files, and keep it stable: changing it changes every URL on the site.

The setting also decides the form of the URLs the build writes into the canonical link, `og:url`, `sitemap.xml` and the `hreflang` alternates, so they name the URL your host answers with the page: `/about/` with `"always"` and `/about` with `"never"`.

## The 404 page

Add `pages/404.json` (or `404.md`) and the build writes it to `dist/404.html`, the file name Cloudflare Pages, GitHub Pages and Netlify serve for a URL that matches nothing. It lands there under either `trailingSlash` setting, gets no canonical link and no Markdown copy, and stays out of the sitemap.

Without one, Cloudflare Pages assumes a single-page application and answers every unknown path with your home page and a 200, so a mistyped link never looks broken to a visitor or a crawler.

A `404.html` in `public/` is copied over the built one, for a page you would rather write by hand. `jx preview` serves `dist/404.html` for unknown URLs, so you see the same page locally.

## Adapters

Without an adapter (the **Static** choice in Studio), the build is just `dist/`: HTML, CSS, JS, and assets for any static host or CDN. Setting `build.adapter` additionally packages the site's server tier, meaning state entries with `timing: "server"` plus the server mounts of enabled extensions, into a single deployable worker:

| Adapter                | Extra output                                                              |
| ---------------------- | ------------------------------------------------------------------------- |
| *(none / static)*      | Nothing; plain `dist/`                                                    |
| `"cloudflare-workers"` | `dist/worker.js`, a Hono server that also serves the static assets        |
| `"cloudflare-pages"`   | `dist/_worker.js` + `dist/_routes.json`, only when there is a server tier |
| `"node"` / `"bun"`     | `dist/worker.js`, a Hono server for that runtime                          |

### What the worker serves

Three route families, and nothing else:

| Route                  | Served by                                                      |
| ---------------------- | -------------------------------------------------------------- |
| `/_jx/auth/*`          | The auth extension: sign-up, sign-in, sign-out, session lookup |
| `/_jx/data/*`          | The connector extension: table CRUD                            |
| `/_jx/server/<export>` | One route per `timing: "server"` state entry                   |

**Pages are never rendered per request.** Every route is prerendered at build time and served as static HTML; the worker answers the `/_jx/*` API surface and falls through to the assets for everything else. Interactivity arrives by hydration, so a page that shows signed-in content ships its signed-out state in the HTML and swaps once the session resolves in the browser. See [Auth and secrets](/docs/studio/data/auth-and-secrets).

Details worth knowing:

- Server functions are collected from every component and page, deduplicated by export name, and bundled once, so there are no per-route server files when an adapter is set.
- The worker is **self-contained**: hono, extension mounts, database connectors, and your server modules are inlined at build time, so `dist/` deploys and runs with no `node_modules` and no deploy-time bundling step.
- On Cloudflare Pages, `_routes.json` limits worker invocation to `/_jx/*`, so static assets are served without waking the worker. A Pages site with no server functions and no mounts gets no worker at all, and the deployment stays purely static.
- A project with dynamic sections (a non-empty `data`/`connections` or `auth` section, served by extension mounts) **must** set a server-capable adapter. On static the build stops with an error naming the offending sections, since a static site has nothing to serve live data with.
- Switching hosts means switching the adapter; your source never changes.

## Serving from a subfolder

Most sites live at the root of a domain. Some don't: a preview at `example.pages.dev/m/my-site/`, a docs site under `/docs/`, a project parked in a subfolder of a bigger server. Every link and asset a build writes starts with a slash, which means *from the site root*, so a build that assumed the root would ask the host for `/assets/app.js` when the file is actually at `/m/my-site/assets/app.js`. The page comes up blank, because the runtime scripts are the first things to 404.

You don't configure this. **Set `url` to where the site actually lives**, including the path:

```json&#x20;shiki
```

That is the same `url` that already drives canonical links and the sitemap, and now it also tells the build where the site's root is. Everything follows from it: page links and images, the import map, component scripts, `_headers` patterns, `_redirects` on both sides, the service worker's precache list and scope, and `manifest.webmanifest`. Canonical links and `sitemap.xml` keep the folder in their absolute URLs instead of dropping it.

Nothing changes for a site at a domain root. `"url": "https://example.com"` has no path, so there is no prefix and the output is byte-for-byte what it was.

Three things stay as you wrote them, because they don't mean *from the site root* in the first place: full URLs (`https://…`), links that start with `./` or `../`, and plain fragments (`#top`).

The build re-roots the URLs it writes, in pages and in the modules it generates: a component's `$src` import, including the dynamic one a `$lazy` function becomes, names the bundle under your path. It does not rewrite your own code. A URL in a string your script holds, or in a prop a component renders at runtime, is yours to build from `$site.url`.

Tip

`bunx jx dev`
&#x20;answers both spellings.&#x20;
`localhost:3000/`
&#x20;works exactly as before, and&#x20;
`localhost:3000/m/my-site/`
&#x20;serves the same pages, so you can click through the URLs the build actually emits without deploying first.

## Hooking up a host

The recipe is the same everywhere: build command `bunx jx build`, publish directory `dist`. [Other hosts](/docs/studio/publish/other-hosts) walks through Netlify and GitHub Pages, and [Cloudflare Pages](/docs/studio/publish/cloudflare) is built into Studio's publish flow.

## Related

- [The build pipeline](/docs/framework/build): what happens between source and `dist/`
- [Redirects](/docs/framework/site/redirects): the `_redirects` file in the output
- [SEO and metadata](/docs/framework/site/seo): `sitemap.xml` and `robots.txt` generation
- [Databases](/docs/studio/data): the tables behind `/_jx/data`, and why they need an adapter
- [Timing](/docs/framework/concepts/timing): how a `timing: "server"` entry becomes a `/_jx/server/` route

✕

Start here[Overview](/docs/start/)Get started[Install Jx Studio](/docs/start/install/)[Your first project](/docs/start/first-project/)[A tour of Jx Studio](/docs/start/studio-tour/)Tutorials[Tutorial: interactive component](/docs/start/first-component/)[Tutorial: blog with collections](/docs/start/first-collection/)[Video tutorials](/docs/start/videos/)Coming from another tool[Coming from WordPress](/docs/start/coming-from-wordpress/)[Coming from Webflow or Framer](/docs/start/coming-from-webflow/)[Coming from Wix or Squarespace](/docs/start/coming-from-wix/)[Coming from Lovable or Builder.io](/docs/start/coming-from-ai-builders/)Studio[Overview](/docs/studio/)[The desktop app](/docs/studio/desktop/)The workspace[Overview](/docs/studio/interface/)[Welcome screen](/docs/studio/interface/welcome-screen/)[Editors and views](/docs/studio/interface/modes/)[The canvas](/docs/studio/interface/canvas/)[Documents and panes](/docs/studio/interface/tabs/)[Quick Access](/docs/studio/interface/quick-access/)[Keyboard shortcuts](/docs/studio/interface/shortcuts/)[Preferences](/docs/studio/interface/preferences/)[Languages](/docs/studio/interface/languages/)[Problems and progress](/docs/studio/interface/problems-and-progress/)[Commands](/docs/studio/interface/commands/)Projects[Overview](/docs/studio/projects/)[Create a project](/docs/studio/projects/create/)[Pages, layouts, components](/docs/studio/projects/pages-layouts-components/)[The Content workspace](/docs/studio/projects/browse/)[Starter templates](/docs/studio/projects/starters/)[Media](/docs/studio/projects/media/)[Content types](/docs/studio/projects/content-types/)[Project settings](/docs/studio/projects/settings/)[Dependencies and imports](/docs/studio/projects/dependencies/)Edit mode[Overview](/docs/studio/editing/)[Writing and formatting](/docs/studio/editing/writing/)[Slash commands](/docs/studio/editing/slash-commands/)[Frontmatter and metadata](/docs/studio/editing/frontmatter/)[Grid mode](/docs/studio/editing/grid/)Design mode[Overview](/docs/studio/design/)[Outline](/docs/studio/design/layers/)[Insert](/docs/studio/design/elements/)[Content tab](/docs/studio/design/properties/)[Style inspector](/docs/studio/design/style-inspector/)[Breakpoints](/docs/studio/design/breakpoints/)[States and selectors](/docs/studio/design/states-and-selectors/)[Design tokens](/docs/studio/design/tokens/)[Project Styles](/docs/studio/design/stylebook/)[Working with components](/docs/studio/design/components/)[Repeaters](/docs/studio/design/repeaters/)Logic[Overview](/docs/studio/logic/)[Formulas and expressions](/docs/studio/logic/formulas/)[Formula workspace](/docs/studio/logic/formula-workspace/)[Statements](/docs/studio/logic/statements/)[Logic tab](/docs/studio/logic/events/)[Data](/docs/studio/logic/data/)[Data sources](/docs/studio/logic/data-sources/)[Code editing](/docs/studio/logic/code/)Databases[Overview](/docs/studio/data/)[Connections](/docs/studio/data/connections/)[Data tables](/docs/studio/data/tables/)[Data grid](/docs/studio/data/grid/)[Auth and secrets](/docs/studio/data/auth-and-secrets/)AI assistant[Overview](/docs/studio/ai/)[The AI assistant](/docs/studio/ai/chat/)[Document assistant](/docs/studio/ai/document-assistant/)Publish[Overview](/docs/studio/publish/)[Source control](/docs/studio/publish/source-control/)[GitHub](/docs/studio/publish/github/)[Cloudflare Pages](/docs/studio/publish/cloudflare/)[Other hosts](/docs/studio/publish/other-hosts/)[Redirects](/docs/studio/publish/redirects/)[Real-time collaboration](/docs/studio/publish/collaboration/)Framework[Overview](/docs/framework/)Concepts[Documents](/docs/framework/concepts/documents/)[Elements](/docs/framework/concepts/elements/)[Components](/docs/framework/concepts/components/)[Props and scope](/docs/framework/concepts/props-and-scope/)[State](/docs/framework/concepts/state/)[Reactivity](/docs/framework/concepts/reactivity/)[References](/docs/framework/concepts/references/)[Expressions](/docs/framework/concepts/expressions/)[Statements](/docs/framework/concepts/statements/)[Functions and sidecars](/docs/framework/concepts/functions/)[Styling](/docs/framework/concepts/styling/)[Color schemes](/docs/framework/concepts/color-schemes/)[Popovers and overlays](/docs/framework/concepts/overlays/)[Accessibility](/docs/framework/concepts/accessibility/)[Lists and iteration](/docs/framework/concepts/lists/)[Data prototypes](/docs/framework/concepts/data-prototypes/)[Timing](/docs/framework/concepts/timing/)[Dynamic switching](/docs/framework/concepts/switching/)[Security](/docs/framework/concepts/security/)Site architecture[Overview](/docs/framework/site/)[project.json](/docs/framework/site/project-json/)[Routing](/docs/framework/site/routing/)[Layouts](/docs/framework/site/layouts/)[Content collections](/docs/framework/site/content-collections/)[Jx Markdown](/docs/framework/site/jx-markdown/)[Obsidian vault as content](/docs/framework/site/obsidian-vault/)[Relationships](/docs/framework/site/relationships/)[SEO and metadata](/docs/framework/site/seo/)[Locales and languages](/docs/framework/site/i18n/)[Images](/docs/framework/site/images/)[Redirects](/docs/framework/site/redirects/)[Feeds](/docs/framework/site/feeds/)[Site search](/docs/framework/site/search/)[Build output and adapters](/docs/framework/site/deployment/)How compilation works[Overview](/docs/framework/build/)[The dev server](/docs/framework/build/dev-server/)[CLI commands](/docs/framework/build/cli/)Working with agents[Overview](/docs/framework/agents/)[Authoring rules for agents](/docs/framework/agents/authoring-rules/)[Machine-readable docs](/docs/framework/agents/machine-readable/)Reference[Overview](/docs/framework/reference/)[Formula catalog](/docs/framework/reference/formulas/)[Operator reference](/docs/framework/reference/operators/)Extending[Overview](/docs/extending/)Extensions[Extension anatomy](/docs/extending/extensions/anatomy/)[Schema composition](/docs/extending/extensions/schema-composition/)[Custom classes](/docs/extending/extensions/classes/)[Custom formats](/docs/extending/extensions/formats/)[Capability methods](/docs/extending/extensions/capabilities/)[Project sections](/docs/extending/extensions/project-sections/)[Server mounts](/docs/extending/extensions/server/)[Connectors](/docs/extending/extensions/connectors/)[Search indexes](/docs/extending/extensions/search/)[Security and secrets](/docs/extending/extensions/security/)[Tutorial: a TOML format](/docs/extending/extensions/tutorial-toml-format/)[Tutorial: a guestbook](/docs/extending/extensions/tutorial-guestbook/)[First-party extensions](/docs/extending/extensions/first-party/)Embedding[Overview](/docs/extending/embedding/)[Hosting the Studio assets](/docs/extending/embedding/hosting/)[Writing a platform adapter](/docs/extending/embedding/platform-adapter/)[The backend protocol](/docs/extending/embedding/backend-protocol/)[Dev server internals](/docs/extending/embedding/dev-server/)[Embedding the runtime in your app](/docs/extending/embedding/runtime-host/)[Writing assistant tools](/docs/extending/embedding/assistant-harness/)UI kit[The Jx UI kit](/docs/extending/ui-kit/)Reference[Protocol routes](/docs/extending/reference/studio-routes/)[Implementation status](/docs/extending/reference/implementation-status/)[Spec changelog](/docs/extending/reference/spec-changelog/)[Standards alignment](/docs/extending/reference/standards/)Contributing[Working in the monorepo](/docs/extending/contributing/monorepo/)[Contributing to these docs](/docs/extending/contributing/docs/)[AI assistant evals](/docs/extending/contributing/ai-evals/)

[![Jx Suite](/favicon.svg)
Suite](/)The visual IDE for the web. Build any website, save it as plain files, own it forever. MIT licensed.

Product

[Studio](/studio)[Download](/download)[Templates](/templates)[Features](/features)[Compare](/compare)[Jx Cloud (soon)](/cloud)

Developers

[Docs](/docs/start/first-project)[Framework](/framework)[Get Studio](/docs/start/install)[Spec](/docs/framework)[GitHub](https://github.com/jxsuite/jx)

Project

[MIT License](https://github.com/jxsuite/jx/blob/main/LICENSE)[Releases](https://github.com/jxsuite/jx/releases/latest)[Privacy](/privacy)[Terms](/terms)[Support](/support)

Built with Jx Suite. © 2026 Avunu LLC. Open source under the MIT License.
