Documentation
Docs
Introduction
Getting Started
Tutorial: build an app
Core Concepts
Routing
Server-Side Rendering
Mimir, state management
Pages & Layouts
API Routes
Styling & Theming
Building & Deploying
API Reference
Guides
Recipes
FAQ (use cases)
The build
ekko build --client is the one build command a rune app needs. It compiles your pages and the hydration
bootstrap into a code-split, content-hashed browser bundle and writes a manifest the server reads.
The server itself transpiles its own (server-side) code as it runs, there is no separate server build step.
What it produces
writes:
.ekko/build/
client/
_hydrate-ZTXJDWFL.js # the hydration bootstrap (runs first in the browser)
pages/index-LNH6OYEF.js # one chunk per page, content-hashed
pages/docs-SOX5ENF4.js
chunks/chunk-5UQ65DYX.js # shared code split out
...
manifest.json # maps pages → chunks (see The manifest)A successful run prints the chunk count and the manifest path:
Building client bundles (N entries + hydrate)...
→ 84 chunks to .ekko/build/client/
→ manifest: .ekko/build/manifest.jsonWhat the build does, conceptually
- Finds the client entry points , your page modules (the ones registered as routes) and the hydration
bootstrap.
- Bundles with the built-in esbuild , transpiles TSX/TS, resolves imports (including
@ekko/*packages
from the store), tree-shakes, and code-splits: shared code becomes chunks/*, each page becomes its
own pages/* chunk that imports the chunks it needs.
- Content-hashes every output filename (
index-LNH6OYEF.js), so files can be cached forever and a change
always produces a new name.
- Writes the manifest mapping each page to its chunk, its imports (to preload), and its CSS.
How the server uses it
readManifest() loads manifest.json; createApp({ manifest }) uses it to emit, per page, the right
<script type="module"> (the hydration entry) and <link rel="modulepreload"> tags (the page chunk and its
imports). The build output is served at /_ekko with a long, immutable cache. See
The manifest.
Server code is not bundled
Only client code is built ahead of time. Your server.tsx, your ssr() functions, your API handlers,
anything that runs on the server, is transpiled and executed by the runtime as the server runs. That is why
you can edit server.tsx and just restart: there is no server build artifact to regenerate.
The practical split:
| Code | Built by | Refresh by |
|---|---|---|
| Pages' client behaviour, hydration | ekko build --client | rebuild + restart |
server.tsx, ssr(), API handlers | the runtime at run time | restart |
styles/global.scss | compileSass at server start | restart |
See The dev loop.
When to rebuild
Rebuild the client whenever code that runs in the browser changes, a page's JSX, a component it renders, client logic. A reliable always-correct command is:
Build it on your dev machine, ship the output
The build needs esbuild, which lives in the EkkoJS store on your dev machine. Production boxes do not have
it (and do not need it): you build the client locally and ship .ekko/build as part of the app. The prod
server reads the prebuilt manifest and serves the prebuilt chunks. Trying to run ekko build --client on a
bare prod box fails with "esbuild not found", that is expected. See
Production deploy.
The .ekko/build folder
- It is generated, do not edit it by hand.
- It is shipped to production (it is in your
package.include). - It is safe to delete and regenerate (
ekko build --client); never leave a stale build, rebuild after
changing client code.
Next: serving images, fonts, and other files, Static assets.