Site architecture
Studio manages this structure for you — Browse your project maps to
pages/,components/, andcontent/; the content-type builder writes thecontentsection; Project settings editsproject.json. This section documents the on-disk layout for reference.
A Jx site is a folder of plain JSON and Markdown files with a conventional layout. Only
project.json
and
pages/
are required — everything else is optional and additive.
Project anatomy
my-site/
├── project.json # Site configuration (required)
├── pages/ # File-based routing (required)
│ ├── index.json # → /
│ ├── about.json # → /about
│ └── blog/
│ ├── index.json # → /blog
│ └── [slug].json # → /blog/:slug (dynamic)
├── layouts/ # Shared page shells
│ └── base.json
├── components/ # Reusable Jx components
├── content/ # Content collections
│ └── blog/
│ └── hello-world.md
├── data/ # Static data files
├── public/ # Static assets (copied verbatim)
└── dist/ # Build output (generated)
| Directory | Purpose | Required |
|---|---|---|
pages/ |
File-based routing. Each page file becomes a route. | Yes |
layouts/ |
Layout components, referenced by pages via
$layout
. |
No |
components/ |
Reusable components, referenced via
$ref
or
$elements
. |
No |
content/ |
Content collections with schema validation. | No |
data/ |
Static data files loaded at build time. No schema enforcement. | No |
public/ |
Static assets copied verbatim to
dist/
. No processing. |
No |
dist/ |
Build output. Ignored by git. | Generated |
Files and directories whose names start with
_
inside
pages/
are excluded from routing, so components can live next to the pages that use them (
pages/blog/_blog-card.json
).
Configuration
project.json
at the project root is the only required configuration file. It names the site, sets the default layout and language, declares global
<head>
entries, breakpoints, and design tokens, and holds the
content
,
redirects
,
copy
, and
build
sections — plus any section an enabled extension contributes:
connections
and
data
for databases,
auth
for visitor accounts,
search
for the build-time search index. Site-level
state
and
$defs
cascade into every page. See
project.json
.
Routing
Every file in
pages/
becomes a route automatically:
pages/about.json
serves
/about
,
pages/blog/[slug].json
is a dynamic route with a
slug
parameter, and
pages/docs/[...path].json
catches everything under
/docs/
. Dynamic pages declare the concrete paths they generate with
$paths
— usually by pointing at a content collection. See
Routing
.
Layouts
Layouts are ordinary Jx documents that provide the shared page shell — navigation, footer, and the
<slot>
elements where page content lands. Pages opt in with
$layout
, or inherit the site default. Named slots, nesting, and state merging follow the same rules as custom elements. See
Layouts
.
Content collections
The
content
section of
project.json
turns folders of Markdown, JSON, or CSV files into typed, queryable collections with JSON Schema validation. Pages query them with
ContentCollection
and
ContentEntry
state entries, and schema
$ref
s link entries across collections — see
Content collections
and
Relationships
.
Markdown pages and content
Markdown is a first-class authoring format: content entries and even whole pages (
pages/index.md
) can be written in Jx Markdown, with frontmatter for metadata and directives for embedding components. See
Jx Markdown
.
SEO and metadata
Pages declare
<head>
entries with
$head
, merged in a fixed order with layout- and site-level entries; titles, canonical URLs, sitemaps, and structured data are handled at build time. See
SEO and metadata
.
Images
Images referenced from pages and content are optimized during the build — resized to multiple widths and re-encoded to modern formats, configured by the
images
section of
project.json
. See
Images
.
Redirects
The
redirects
map in
project.json
declares old-URL-to-new-URL rules, including
:param
patterns and per-rule HTTP status codes. See
Redirects
.
Databases, accounts, and server functions
Not everything a site shows has to be a file. With the
@jxsuite/connector
extension enabled,
connections
names the databases the site talks to and
data
declares the tables inside them, served over
/_jx/data
; with
@jxsuite/auth
, the
auth
section gives visitors accounts and sessions at
/_jx/auth
and unlocks the table permission rules that depend on knowing who is asking. Separately, any
state
entry marked
timing: "server"
compiles into its own route at
/_jx/server/<export>
, so secrets and privileged calls stay off the client. The connection-backed sections require a server-capable
build.adapter
— the build stops without one — and server functions need somewhere to run for the same reason. See
Databases
,
Auth and secrets
, and
Timing
.
Building and deploying
bunx jx build
discovers routes, compiles each page, and emits static HTML, CSS, and minimal JS into
dist/
— deployable to any static host. With
build.adapter
set, the same command also bundles the site's server tier —
timing: "server"
functions and extension mounts such as
/_jx/data
and
/_jx/auth
— into one self-contained worker. Pages are prerendered either way; the worker only answers
/_jx/*
and, on some adapters, serves the static files. See
the build pipeline
and
Deployment
; Studio itself never runs this step — it
commits and pushes your source
, and your host builds on push.