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)
Project structure
A rune project is a set of conventional folders. The conventions are load-bearing, the framework derives routes, layouts, and the build from the layout on disk, so it pays to know what each folder is for.
my-app/
server.tsx # entry: wires the app together and calls app.start()
ekko.json # project config (type "run", permissions, dependencies)
ekko.lock # resolved dependency versions from the store
pages/ # routes, one module per URL
index.tsx # /
about.tsx # /about
blog/
index.tsx # /blog
[slug].tsx # /blog/:slug
layout.tsx # root layout (the shell)
not-found.tsx # 404 page
error.tsx # error page
components/ # reusable UI, not routes
atoms/ # Mimir atoms (shared, reload-tolerant state)
lib/ # plain TS modules (config, helpers, theme objects)
styles/
global.scss # the design system; compiled at server start
static/ # files served verbatim under /assets (images, fonts, svg)
content/ # data sources (e.g. docs markdown + generated data)
_build/ # local build scripts (e.g. docs converter)
.ekko/build/ # GENERATED by `ekko build --client` (client bundle + manifest)The folders that matter, and why
pages/
The router's source of truth. Every .tsx/.jsx/.ts/.js file is a route, except the convention
files (layout, loading, error, not-found, and their _-prefixed variants), which have special
meaning. File names map to URLs:
index.tsx→ the folder's root (pages/index.tsx→/,pages/blog/index.tsx→/blog)[param].tsx→ a dynamic segment (:param)[...rest].tsx→ a catch-all (*rest)(group)/→ a grouping folder that is stripped from the URL
Full rules in File-based routing.
A page module exports a default component and may export ssr() (server-only metadata + seed
state). See Pages.
Import code without the extension. Files on disk carry
.tsx/.ts, but you import them as./pages/about, not./pages/about.tsx. Ekko owns resolution and rejects extensioned specifiers at run. See Why extensionless? for the reasoning.
components/
Plain React components that are not routes. Nothing magic, import and use them in pages or other components.
atoms/
By convention, your Mimir atoms live here, one small module per concern (theme, cart, UI flags). Atoms are the right home for any state that must outlive a navigation or a refresh. See Mimir.
lib/
Ordinary modules: site configuration (site.ts with the name, URL, nav links), theme objects for
@ekko/asgard (theme.ts), and helpers. Imported by server.tsx and your pages.
styles/
global.scss is your design system, typically CSS custom properties on :root (light) and .dark. It is
compiled to CSS at server start with compileSass(readText("styles/global.scss")) and injected into the
document head. See Styling.
static/
Anything here is served verbatim. With static: "./static", staticPrefix: "/assets", a file at
static/logo.svg is available at /assets/logo.svg. Good for images, fonts, and SVG diagrams.
content/
A convention for data sources. In a docs site, content/docs-src/*.md is the markdown you edit and
content/docs/docs.data.ts is the generated, embedded data the app imports. Computed once, served from
memory.
.ekko/build/
The output of ekko build --client: the hashed client chunks under .ekko/build/client/ and the
manifest.json the server reads. Do not edit by hand; rebuild it. It is shipped to production as part
of the app bundle (the prod box does not rebuild client code).
server.tsx , the one file that ties it together
Every line here is explained in its own chapter, The application for
createApp, Routing, SSR,
API routes, SEO, and Styling.
Next: The dev loop.