Getting started

From zero to a running app.

If you can write x-data, you can build a full-stack, server-rendered app. Scaffold a project, run the dev server, then follow the dev → build → deploy lifecycle.

Requirements #

Apex runs on Node.js (20.19+) with any package manager (npm, pnpm, yarn). It is Node-native — no PHP, no other runtime. TypeScript is set up for you.

Scaffold a project #

Install the CLI once, then the whole lifecycle is apex …:

npm i -g @apex-stack/core   # install the Apex CLI
apex new my-app             # scaffold, install deps, init git
cd my-app
apex dev

apex new installs dependencies with your package manager (npm/pnpm/yarn/bun) and initializes git — pass --no-install or --no-git to skip. Rather not install globally? Use npm create apexjs@latest my-app and run the CLI locally with npm run dev (or npx apex dev). The libraries live under the @apex-stack/* scope (@apex-stack/core is the CLI + runtime).

Global vs. local

With the global install, apex works in any project. Without it, apex is a project-local binary (like next or vite) — run it via npm run dev or npx apex dev. A bare apex only resolves once it's installed globally.

The Apex JS starter page running in a browser, showing the welcome heading and a Show me how button.
The starter you get out of the box — server-rendered, then hydrated.

Project structure #

A fresh app is intentionally small. Everything is a file in a known place:

my-app/
├─ pages/
│  └─ index.alpine        # a route → "/"  (SSR + hydrate)
├─ server/
│  └─ api/
│     └─ hello.ts         # REST endpoint AND MCP tool
├─ package.json
└─ .gitignore
LocationWhat it holds
pages/**/*.alpineRoutes. File path → URL. [param] segments are dynamic. See Routing.
components/*.alpineReusable .alpine components embedded as <PascalCase />. See Components.
server/api/*.tsTyped API routes (defineApexRoute) and data resources (defineResource). REST + MCP. See AI-native.
db/Schema, createDb, and db/migrations/*.sql. See Data.
public/Static assets copied verbatim into the build output.

components/, db/, and public/ are optional — add them when you need them (or generate files with apex make).

Run the dev server #

The scaffold wires two scripts. Start the standard dev server:

npm run dev          # apex dev  → http://localhost:3000
npm run dev:islands  # apex dev --islands (static-first)

The dev server is Vite in middleware mode fronted by an h3 app. It server-renders every .alpine page, serves your server/api/* routes at /api/*, and exposes their MCP tools at /mcp. Pass --port to change the port.

Islands mode

apex dev --islands renders pages static-first and hydrates interactive regions individually, on a trigger — a page with no islands ships zero framework JS. See Islands.

Your first edit #

Open pages/index.alpine. A page is one file: a server loader(), an Alpine <template>, and scoped CSS. The loader() runs on the server and its return value becomes the Alpine x-data scope — no fetch, no boilerplate.

pages/index.alpine

<script server lang="ts">
  export function loader() {
    return { title: 'Welcome to Apex JS' }
  }
</script>

<template x-data="{ open: false }">
  <main>
    <h1 x-text="title"></h1>
    <button @click="open = !open">Toggle</button>
    <p x-show="open">Hydrated in the browser.</p>
  </main>
</template>

<style scoped>
  main { max-width: 40rem; margin: 4rem auto; }
</style>

Change the title string and save — the browser updates on its own. The full .alpine format (loader, template, scoped style, embedding) is covered in Components.

Hot reload #

Dev reloads are automatic and scoped to what you changed:

  • .alpine pages, components, and styles — a full page reload on save, so SSR output and hydration always match.
  • server/api/*.ts routes and resources — reloaded per request. Editing a handler, a Zod schema, or a resource takes effect on the next request, no dev-server restart v0.1.4.

The dev → build → deploy lifecycle #

One project, three commands, from local iteration to production:

StageCommandWhat happens
Developapex devSSR + hydrate with hot reload; API + MCP live at /api and /mcp.
Buildapex buildPrerender pages + per-page client bundle → static dist/. --islands for zero-JS SSG; --server for a Node server.
Migrateapex migrateApply db/migrations/*.sql (a deploy step for apps with a database).
Serveapex startRun the production Node server built by apex build --server (dynamic routes + API/MCP + DB).

The three build modes and hosting targets are covered in full on Build & deploy.

Next steps #