HTML-first apps.
AI-native APIs.

Apex is to Alpine what Next.js is to React — file routing, server rendering, and islands. Then it does what no other framework does: every typed API route is also an MCP tool your AI can call. No extra library.

$ npm i -g @apex-stack/core Get started → GitHub

The anatomy of an Apex app

A real project, file by file.

Click through the tree — every file is the actual code Apex scaffolds. Folders nest with proper indent guides, so pages/blog/[slug] sits two levels deep, not flat.

my-app — Apex JS workspace
Explorer
index.alpine — pages/ ALPINE SFC
1
Terminal dev server
PS C:\dev\my-app> apex dev

  v0.1.20  ·  The full-stack, AI-native meta-framework for Alpine.js
   Dev server ready

    Local   http://localhost:3000/
    MCP     http://localhost:3000/mcp
my-app · /blog GET /api/posts → 200

Publish a post

The same code, running on sample data — no database. Posts a JSON body and prepends the result.

Everything you need, in one framework.

File routing, server rendering, islands, components, a typed data layer, and AI-native APIs — the essentials, out of the box.

server/api/features.ts — the whole backend of the demo

// One definition → REST endpoints AND MCP tools
// (features_list / get / create / update / delete). The UI
// below and an AI assistant call the SAME handlers.
export default defineResource('features', {
  db,
  table: schema.features,
  insert: { name: z.string(), tag: z.string().optional() },
})

pages/index.alpine — the list is rendered from the DB on the server

<script server lang="ts">
  import { db, schema } from '../db/index.js'
  export async function loader() {
    const features = await db.select().from(schema.features)
    return { features }   // → Alpine x-data, in the first HTML
  }
</script>

The browser's "Add" and the "Simulate an AI" button both POST /api/features — the exact endpoint exposed as the MCP tool features_create. One defineResource, and the UI and an assistant operate on the same rows. See the Data guide →

Server-first

Real HTML on first paint

Every page renders on the server from a typed loader() — fast, crawlable, no client round-trip.

Islands

Ship almost no JavaScript

Static by default; regions hydrate on client:load | idle | visible. A page with no islands ships zero framework JS.

Data

One definition, two surfaces

defineResource turns a table into REST endpoints and MCP tools — one database, no drift.

Reusable logic

Composables & shared stores

Import useX() into x-data, and share reactive state across pages, components and islands with $store.

AI-native

Every route is an MCP tool

The part no one else has: expose a typed route and an assistant can call it — no extra library.

Three pillars

Light where it counts. Full-stack where you need it. AI-native by default.

Light

Ship almost no JavaScript

Static-first pages. Islands hydrate only when they need to — many pages ship zero framework JS until you scroll.

<!-- wakes on scroll, not on load -->
<section x-data="{ n: 0 }" client:visible>
  <button @click="n++" x-text="n"></button>
</section>
Full-stack

Routing, SSR, typed routes

File-based routing, server-side rendering, and a component you already know how to write. On Node — no PHP required.

// pages/blog/[slug].alpine
<script server>
  export function loader({ params }) {
    return { post: getPost(params.slug) }
  }
</script>
AI-native

Your API is a tool

Write a route once. It's a REST endpoint and an MCP tool. Point Claude at /mcp and it can call your app.

// server/api/add.ts
export default defineApexRoute({
  description: 'Add two numbers',
  input: { a: z.number(), b: z.number() },
  mcp: true,
  handler: ({ input }) => ({ sum: input.a + input.b }),
})

The unfair advantage

One definition. Two surfaces.

Because every route carries a strict, typed schema, exposing it to an AI is automatic. The framework carries the MCP transport — you install nothing extra.

defineApexRoute
server/api/add.ts
↓ generates ↓
REST endpoint
POST /api/add → { "sum": 5 }
MCP tool
tools/call add → { "sum": 5 }

Read the AI-native guide →

Quickstart

Scaffold and run in under a minute.

# install the CLI once, then use `apex` everywhere
npm i -g @apex-stack/core
apex new my-app        # scaffold + install deps + git init
cd my-app
apex dev               # http://localhost:3000
apex dev --islands     # static-first islands mode

apex new installs everything and sets up git for you; the app ships a server-rendered page (pages/index.alpine) and an API route that is also an MCP tool (server/api/hello.ts). Don't want a global install? Run npm create apexjs@latest my-app and use npm run dev — same result, local CLI.

Early, but real

Not a manifesto — a working framework.

3
Pillars, all shipping
76
Tests passing
~15KB
Alpine — one runtime
MIT
Built in the open
Status · v0.1.4

Apex JS is on npm under @apex-stack/*. SSR + hydration, islands, file routing, components, AI-native APIs, a multi-database data layer, and a full production build (static or Node server) are all proven and covered by tests. Jobs/queues and Nitro deploy presets are next — see the roadmap.