Runable v1.0.0-alpha.20
Why Runable? Docs Modules Work with AI Blog About Changelog
  • 01Why Runable?
  • 02Docs
  • 03Modules
  • 04Work with AI
  • 05Blog
  • 06About
  • 07Changelog
Vue without a fixed server runtime.
Getting Started Structure Integrations Guide MCP API
  • Getting Started Structure Integrations Guide MCP API
  • Why Runable
  • Installation
  • Quick Start
  • Runable vs Nuxt
  • Configuration
  • Concepts

Concepts

Understand the backend, Runable engine, Vue application, generated files, and SSR lifecycle.

Runable connects three layers: your HTTP server, the framework engine, and your Vue application.

Three responsibilities

LayerResponsibility
Your backendListen on the network, run API routes, and handle application logic
RunablePrepare the application, generate conventions, and produce the frontend response
Your Vue applicationDefine pages, components, layouts, and user interactions

This separation lets you replace Express with Fastify or Hono without reorganizing Vue files.

The backend remains the entry point

Runable does not automatically start your application server. You create the server, then forward frontend requests to it.

// server.ts
import Express from "express";
import { express } from "runable/adapters/express";

const server = Express();

server.get("/api/orders", ordersController);
server.use(express());

server.listen(3000);

You control the order. Place API routes before the Runable adapter so the backend handles them first.

Adapters for each backend

Each adapter initializes Runable once and translates framework objects for the rendering engine:

AdapterEnvironment
express()Express middleware
fastify()Fastify plugin
hono()Hono middleware
koa()Koa middleware
RunableModule.register()NestJS module on the Express platform
adonis()AdonisJS catch-all route handler
bun()fetch function for Bun.serve()
deno()fetch function for Deno.serve()

Node adapters use Node request and response objects internally. Bun and Deno adapters use standard Request and Response objects.

Connect other backends

Always place the adapter after API routes or as the router's final fallback.

import Express from "express";
import { express } from "runable/adapters/express";

const app = Express();
app.use(express());
app.listen(3000);
import Fastify from "fastify";
import { fastify } from "runable/adapters/fastify";

const app = Fastify();
await app.register(fastify());
await app.listen({ port: 3000 });
import { Hono } from "hono";
import { hono } from "runable/adapters/hono";

const app = new Hono();
app.use("*", hono());

export default app;
import Koa from "koa";
import { koa } from "runable/adapters/koa";

const app = new Koa();
app.use(koa());
app.listen(3000);
import { Module } from "@nestjs/common";
import { RunableModule } from "runable/adapters/nestjs";

@Module({
  imports: [RunableModule.register()],
})
export class AppModule {}
import router from "@adonisjs/core/services/router";
import { adonis } from "runable/adapters/adonis";

router.any("*", adonis());
import { bun } from "runable/adapters/bun";

Bun.serve({ port: 3000, fetch: bun() });
import { deno } from "runable/adapters/deno";

Deno.serve({ port: 3000 }, deno());

Conventions become generated code

At startup, Runable reads runable.config.ts, resolves paths, and configures several Vite plugins.

app/pages/          ──► Vue Router routes
app/layouts/        ──► layout registry
app/components/     ──► available components
app/composables/    ──► automatic imports
app/globals/        ──► auto-imported global functions and variables
app/middlewares/    ──► navigation guards
app/plugins/        ──► plugins installed in Vue

Required declarations and virtual files are written to .app/. This directory is generated; do not use it for source code.

One Vue application per server render

For every SSR render, Runable creates a new Vue application, then installs the router, layouts, plugins, data manager, and Unhead.

This isolation prevents request-specific state from being shared with another user.

Request A ──► Vue App A ──► Cache A ──► HTML A
Request B ──► Vue App B ──► Cache B ──► HTML B

Do not store user-specific data in a global module variable. Use state created in the application context.

The SSR lifecycle

When ssr is true, a request follows these steps:

the backend forwards the URL to Runable;
Vue Router resolves the page and its middleware;
useAsyncData() waits for non-lazy data;
Vue produces HTML and Unhead injects the head;
Runable serializes the data cache into the response;
the browser restores the cache and hydrates the application.

With ssr: false, Runable returns the client template without rendering components on the server.

Pages and metadata

A file in app/pages/ becomes a route:

app/pages/
├── index.vue            → /
├── account.vue          → /account
├── users/[id].vue       → /users/:id
└── docs/[...slug].vue   → /docs/:slug*

definePageMeta() supplements file-name conventions:

<!-- app/pages/account.vue -->
<script setup lang="ts">
definePageMeta({
  layout: "dashboard",
  middleware: ["auth"],
});
</script>

<template>
  <h1>My account</h1>
</template>

Global middleware runs on every navigation. Named middleware is loaded when referenced by a page.

Plugins and modules

A plugin runs when the Vue application is created. It can provide values, register hooks, or install a client integration.

// app/plugins/api.ts
export default defineVuePlugin(() => {
  return {
    provide: {
      apiBase: "/api",
    },
  };
});

A module runs earlier, while configuration loads. It can add directories, plugins, or Vite options to an application.

ExtensionExecution timeTypical use
PluginVue application creationInjection, client SDK, runtime hooks
ModuleConfiguration loadingReusable feature, generation, and configuration

Development and production

In development, createRunableApp() returns a Vite instance in middleware mode. Your backend uses it for HMR and module transformation.

In production, createRunableApp() loads configuration without creating a Vite server. runable build must generate the expected files in .output/ before startup.

DirectoryStatusContent
app/SourceYour Vue application
public/SourceStatic assets
.app/GeneratedTypes, routes, and virtual registries
.output/GeneratedProduction build artifacts

Mental model

Remember this rule: your backend owns HTTP, Runable owns application assembly, and Vue owns the interface.

Getting Started complete

You can now browse the Structure section to understand every directory in a Runable project.

Report an issue Edit this page
Configuration

Configure directories, SSR, metadata, aliases, modules, and Vite options for your application.

Structure

Quickly locate application code, configuration, generated files, and the production build in a Runable project.

On this page

  • 1Three responsibilities
  • 2The backend remains the entry point
  • 3Adapters for each backend
  • 3.1Connect other backends
  • 4Conventions become generated code
  • 5One Vue application per server render
  • 6The SSR lifecycle
  • 7Pages and metadata
  • 8Plugins and modules
  • 9Development and production
  • 10Mental model
Runable

The Vue framework that brings productive conventions to any backend.

Product

  • Why Runable
  • Documentation
  • Installation
  • Integrations

Project

  • About
  • Blog
  • Changelog
  • Sponsor

Community

  • GitHub
  • Issues
  • Discussions
  • Bluesky

© 2026 Runable. Released under the MIT License.

Open source Built with Vue and Runable