# Overview

> What Moddable is, how a project is laid out, and the pieces a module is built from.

Moddable is a full-stack TypeScript framework that compiles a server, a website and a service
worker out of one source tree and ships them as a single Cloudflare Worker. There is no
separate frontend project, no API project, and no build server — there is a tree of modules and
a CLI that turns it into a deployment.

## The shape of a project

A project is `moddable/`. Everything inside it is either a module you compose your
platform from, or a target the CLI writes into.

```
moddable/
├── core/ # the base module — auth, storage, notification, site
├── modules/ # everything else you register
├── cli/ # the `moddable` command, compiled from source
├── common/ # code shared between core and the CLI
├── scripts/ # Bun macros and Vite plugins
├── server/ # build target: the Cloudflare Worker
├── site/ # build target: the browser bundles
├── settings/ # module load order and project settings
├── tests/ # one directory per module
└── types/ # generated type unions
```

`server/`, `site/` and `types/` are generated. You do not edit
them; `moddable config` composes them from the modules that are actually on disk, so
adding a module is a matter of creating a directory and re-running a generator.

## Modules and submodules

A module is a folder with up to three submodules, and the submodule a file lives in decides
where its code ends up:

Submodule |
Compiled into |

`api/` |
The Worker — signals, views, durable objects, routines |

`client/` |
The browser bundle and the service worker |

`shared/` |
Both, merged into each |

Inside a submodule the directory names are the contract. `signals/` holds request
handlers, `views/` holds URL-routed pages, `elements/` holds custom
elements, `objects/` holds durable objects, `routines/` holds scheduled
work, `helpers/` holds the `use*` clients, and
`registration/` holds the lifecycle hooks that run when the module is loaded.

Module order is registration order, and later modules merge over earlier ones. That is the
extension mechanism: a module does not patch core, it registers something at the same key and
wins.

## Signals

A signal is a route plus a handler. It is declared with the pathname it answers to, the
middleware it runs behind, and a handler that switches on the HTTP method.

```
export const authAPISignInSignal = makeSignal('api', '/auth/signin', {
middleware: [useRequestTelemetry],
handler: async (moddable, request, params) => {
const { useRequestSwitch, onRequestException } = moddable.helpers
return useRequestSwitch({ POST }, onRequestException).handle(moddable, request, params)
}
})
```

Signals registered by a module under `api/signals` are served beneath
`/api`, so the signal above answers at `/api/auth/signin`.

## Views and elements

A view is a page. It is a folder — `index.ts` declaring what the page is,
`template.html`, `style.css` and `logic.ts` — and the CLI
compiles it twice: the definition is read on the server so the page can be rendered into HTML,
and the logic is bundled into a custom element the browser upgrades the same markup into.

```
export default makeView({
name: 'DocsView',
tag: 'docs-view',
pathname: '/docs',
layouts: ['docs-layout'],
template,
style,
logic,
hook: (moddable, props, view) => props
})
```

The `hook` runs on the server for every request, before the template is
interpolated. Whatever it returns becomes the page's props — rendered into the HTML and handed
to the browser as JSON, so the client hydrates the exact tree the server sent.

An element is the same folder shape without a pathname. Elements are addressed by tag, listed
in their module's `elements/index.ts`, and served as
`/elements/<tag>.js`. A view names elements in
`layouts` to be wrapped in them.

## One runtime, three outputs

`moddable build` produces the worker bundle, the browser app, and one module per
view, element and asset. The worker serves the site it was compiled with, so a deployment is a
single `wrangler deploy` — there is nothing else to put anywhere.

Read [Quickstart](/docs/quickstart) next to get one running.
