Start a new app
The fastest way to a running Zoijs app is one command:
npm create zoijs@latest my-app
cd my-app
npm install
npm run devThat scaffolds a named app, installs @zoijs/core, and serves it. npm run dev runs a tiny zero-dependency static server (no bundler, no build step):
ZoiJS dev server: http://localhost:7310
If busy: 7311, 7312, 7313The generated files are plain HTML, CSS, and JavaScript you can open and read.
create-zoijs is the official Zoijs starter: a tiny scaffolder, not a toolchain. It writes a few files and gets out of the way.
You don't need the CLI. Zoijs works perfectly without it — it's only a convenience. The no-CLI setup below is just as valid.
Naming your app#
The folder name you pass becomes the project name:
npm create zoijs@latest task-managerproduces a package.json with:
{ "name": "task-manager" }and an index.html with a readable title:
<title>Task Manager</title>If you don't pass a name, the CLI asks one simple question — Project name:.
Templates#
npm create zoijs@latest my-app # default: the "app" template
npm create zoijs@latest my-app --template basic # a minimal counter
npm create zoijs@latest my-app --template app # a small task dashboardapp (default)#
A small task dashboard that demonstrates the whole core in one readable app: createState for the list, computed for the "tasks left" count, each for keyed rendering, and component communication — the parent passes data down to a Header, and TaskItem reports toggle/delete events back up through callbacks.
basic#
The smallest Zoijs app — a counter. One createState, one html template, one mount. Ideal when you want a blank canvas.
Both templates depend only on @zoijs/core.
Project structure#
The generated app is a handful of plain files — nothing hidden:
my-app/
index.html import map + the #app mount point
package.json app name + the dev script
dev-server.mjs tiny zero-dependency static server (npm run dev)
src/
app.js your app: state, markup, mount
style.css plain CSS (light/dark, responsive)
components/ (app template only) small components
Header.js parent to child: hero + summary
StatCard.js parent to child: a reusable stat card
TaskItem.js child to parent: reports events via callbacksThe basic template is the same without the components/ folder. Open any file and read it — that's the whole project.
What the CLI does#
- Copies a template and fills in your app's name (in
package.json, the<title>, and the README). - Validates the name (npm-safe) and refuses to overwrite a non-empty folder.
- Prints the three commands to get going.
What the CLI does not do#
By design, to keep Zoijs simple, there is no build system, bundler, compiler, JSX transform, code generator, plugin system, template DSL, or complex prompts. The generated app is plain files — nothing is hidden.
Set up by hand (no CLI)#
The CLI just saves typing. Here's the same thing by hand.
With npm#
mkdir my-app && cd my-app
npm init -y
npm install @zoijs/coreCreate index.html with an import map pointing at the installed package:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<script type=class="tok-string">"importmap">
{ "imports": { "@zoijs/core": "./node_modules/@zoijs/core/src/index.js" } }
</script>
</head>
<body>
<div id=class="tok-string">"app"></div>
<script type=class="tok-string">"module" src=class="tok-string">"./app.js"></script>
</body>
</html>// app.js
import { html, mount, createState } from "@zoijs/core";
function App() {
const count = createState(0);
return html`<button onclick=${() => count.set(count.get() + 1)}>Clicked ${() => count.get()} times</button>`;
}
mount(App, "#app");Serve it with any static server (npx serve .) and open the printed URL.
With a CDN (zero install)#
No package.json at all — point the import map at a CDN and pin the version:
<script type=class="tok-string">"importmap">
{ "imports": { "@zoijs/core": "https://esm.sh/@zoijs/core@1" } }
</script>Everything else is the same. This is the most minimal possible setup.
Next steps#
- Getting Started — the ideas behind that first app.
- Core Concepts — the one rule that powers everything.
- Component communication — the patterns the
apptemplate uses.