Installation
For the complete documentation index, see llms.txt. Prefer markdown by appending .md to documentation URLs or sending Accept: text/markdown.

Conventions

Follow Edge Kit's conventions for module layout, typed imports, server boundaries, localized copy, and the lint checks that enforce them.

You're not required to follow these conventions; they're simply a standard set of practices used in Edge Kit. If you like them, we encourage you to keep them during your usage of the kit so you have a consistent code style that you and your teammates understand.

Single package

Edge Kit is one package, so there's no decision about where shared code goes. Keep infrastructure adapters in src/lib, product features in src/modules, and let src/routes only compose them. See Project structure.

Imports and paths

  • From the app: use the @/ alias, which maps to src/ (e.g. @/lib/log, @/modules/billing/...). There is no other alias.
  • Env config: env.config.ts lives outside src/, so import it by relative path with the .ts extension.
  • Cloudflare bindings: import env from cloudflare:workers.
  • i18n: keep the .js extension in imports from @/lib/i18n.
import env from "../../env.config.ts"; // typed secrets (envin + Zod)
import { env as bindings } from "cloudflare:workers"; // env.DB, env.KV, ...
import { m } from "@/lib/i18n/messages.js";

Client and server code

  • UI talks to the server through createServerFn handlers, usually in *.functions.ts.
  • Files named *.server.ts read D1, secrets, and bindings. Never import them from client components.
  • TanStack Query options live in *.queries.ts.
  • Link targets come from src/config/paths.ts, not inline string literals.

Use paths configuration for shared route constants and server functions for the client/server boundary.

TypeScript

  • Functional and declarative. No classes, no enums (use as const maps), no any.
  • Prefer interface for object shapes and type for unions and derived types.
  • Validate with Zod 4.
  • Use guard clauses and early returns over nested conditionals.

Internationalization

All user-facing copy goes through Paraglide. The lint rules require translated strings in JSX.

  • Short reusable labels are unprefixed: save, email, home.
  • View-specific copy uses a dotted prefix: auth.login.title.
  • Every segment is camelCase.
  • Keep messages/en.json and messages/es.json in sync.

UI

  • Kumo components are imported by subpath (@cloudflare/kumo/components/button), never from the package root, to keep the bundle small.
  • Icons come from @phosphor-icons/react.
  • Shared app-level UI lives in src/modules/common.
  • Use Tailwind CSS utilities, no inline styles.

Tooling

We don't enforce complex rules that aren't relevant to the project, giving you more freedom to customize things. To enforce these conventions, we use:

Code health

GitHub Actions

By default, Edge Kit sets up GitHub Actions in .github/workflows:

  • tests - runs format, lint, and test on every pull request.
  • e2e - runs Playwright against Chrome, Firefox, and Safari (WebKit). On pull requests it only runs when the PR has the e2e label.
  • publish-web - runs the tests, then deploys the Worker with pnpm run deploy (manual trigger).

Git hooks

A pre-commit hook checks staged files for formatting and linting errors. It's configured using Lefthook:

lefthook.yml
pre-commit:
  parallel: true
  commands:
    format:
      run: pnpm format:fix {staged_files}
    lint:
      run: pnpm lint:fix {staged_files}

Feel free to customize it, e.g. to validate commit messages with commitlint:

lefthook.yml
commit-msg:
  commands:
    "lint commit message":
      run: pnpm commitlint --edit {1}

How is this guide?

Last updated on

On this page

Ship globally on the edge. In minutes.Try Edge Kit