alepha@docs:~/docs/guides$
cat 2-getting-started.md | pretty
4 min read
Last commit:

#Getting Started

This guide takes you from zero to a running Alepha server in under five minutes. No Webpack, no Babel, no ESLint configuration.

#Prerequisites

You need one of the following:

#Create a Project

npx alepha@latest init my-app

This creates a my-app directory with:

  • package.json with Alepha as a dependency
  • tsconfig.json configured for TypeScript
  • alepha.config.ts with documented build options
  • biome.json for formatting and linting
  • src/api/ with an example controller
  • src/web/ with a React router and page
  • src/main.server.ts and src/main.browser.ts as the entry files

Dependencies are installed automatically.

Every Alepha project has this same shape — there are no flags to pick a flavour. One layout means anyone opening the project, human or AI, already knows where things live. If you don't need the frontend, delete src/web/.

The only options are --pm to choose a package manager, --force to overwrite existing files, and --no-devtools:

npx alepha@latest init my-app --pm=bun

#Your First Server

After running init, enter the project:

bash
cd my-app

Open the entry file. It wires up the two generated modules:

src/main.server.ts
 1import { Alepha, run } from "alepha"; 2import { ApiModule } from "./api/index.ts"; 3import { WebModule } from "./web/index.ts"; 4  5const alepha = Alepha.create(); 6  7alepha.with(ApiModule); 8alepha.with(WebModule); 9 10run(alepha);

To see the smallest thing Alepha can do, strip it back to a single route. Replace the file contents with:

src/main.server.ts
 1import { run } from "alepha"; 2import { $route } from "alepha/server"; 3  4class App { 5  hello = $route({ 6    path: "/", 7    handler: () => "Hello, Alepha!", 8  }); 9}10 11run(App);

That $route call is a Primitive -- a factory function that registers an HTTP endpoint directly on your class. No separate router file, no middleware chain.

run(App) creates an Alepha container, registers App, starts the server, and handles signal trapping (SIGINT, SIGTERM) for graceful shutdown.

#Run in Development Mode

npm run dev

You should see:

bash
[02:10:43.013] INFO <alepha.core.Alepha>: Starting App...
[02:10:43.013] INFO <alepha.core.Alepha>: App is now ready [0ms]

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help

Open http://localhost:5173 in your browser. You will see "Hello, Alepha!".

Development mode gives you:

  1. Hot Module Replacement (HMR) -- change code, server updates instantly.
  2. TypeScript support -- no build step required.
  3. Pretty logs -- readable, structured output.

#Add a Typed API Endpoint

$route is low-level. For real APIs, use $action -- it adds schema validation, automatic OpenAPI documentation, and type-safe client calls.

src/main.server.ts
 1import { z, run, $inject } from "alepha"; 2import { $action } from "alepha/server"; 3import { DateTimeProvider } from "alepha/datetime"; 4  5class App { 6  dateTimeProvider = $inject(DateTimeProvider); 7  8  hello = $action({ 9    path: "/hello",10    schema: {11      response: z.object({12        message: z.text(),13        serverTime: z.datetime(),14      }),15    },16    handler: () => ({17      message: "Hello from Alepha",18      // consider using `dateTimeProvider.nowISOString()` instead of `new Date().toISOString()`19      // for better testability and consistency across runtimes20      serverTime: this.dateTimeProvider.nowISOString(),21    }),22  });23}24 25run(App);

Key differences from $route:

  • All $action paths are automatically prefixed with /api. This endpoint serves at GET /api/hello.
  • The schema.response validates the return value and generates OpenAPI documentation.
  • If a schema.body is provided, the method defaults to POST.
  • The response is type-checked at compile time.

Save the file. HMR reloads the server. Visit http://localhost:5173/api/hello.

#Build for Production

When you are ready to deploy:

npm run build

This produces a dist/ folder with an optimized, self-contained bundle.

Run it locally to verify:

bash
node dist

Or with Bun:

bash
bun dist

App starts up just like in development mode, but without HMR and with better performance.

In production, default port is 3000 instead of 5173 to avoid conflicts with development servers. SERVER_PORT environment variable can override this.

#Build Targets

Alepha adapts the build output based on where you deploy:

npm run build -- --target=cloudflare   # Adapts output for Cloudflare Workers
npm run build -- --runtime=bun         # Optimizes for Bun runtime
# or with alepha
npx alepha build

Build targets and runtime can also be set in alepha.config.ts:

alepha.config.ts
1import { defineConfig } from "alepha/cli/config";2 3export default defineConfig({4  build: {5    target: "cloudflare",6    runtime: "workerd",7  },8});

#Deploy to the Cloud

Once your app builds, you can deploy it to Cloudflare Workers in one command.

Add the platform plugin to your config:

alepha.config.ts
 1import { defineConfig } from "alepha/cli/config"; 2import { platform } from "alepha/cli/platform"; 3  4export default defineConfig({ 5  plugins: [ 6    platform({ 7      environments: { 8        production: { adapter: "cloudflare" }, 9      },10    }),11  ],12});

Then deploy:

npx alepha p up

Alepha scans your code for primitives ($entity, $storage, $job, etc.), provisions the matching Cloudflare resources (D1, R2, Queue), builds for Workers, runs migrations, and deploys -- all in one step.

Preview what will be created before deploying:

npx alepha p plan

See the Platform Plugin guide for full configuration, secrets, monorepo support, and teardown.

#Project Structure

alepha init always scaffolds this structure:

bash
my-app/
  alepha.config.ts          # Build and entry point configuration
  package.json
  tsconfig.json
  biome.json
  vite.config.ts            # Tailwind plugin
  src/
    main.server.ts          # Server entry point
    main.browser.ts         # Browser entry point
    main.css                # Global styles (@import "tailwindcss")
    api/
      index.ts              # API module definition
      controllers/
        HelloController.ts  # Example $action endpoint
      schemas/
        helloResponseSchema.ts
    web/
      index.ts              # Web module definition
      AppRouter.ts          # $page routes
      components/
        Home.tsx            # Example React component

#Devtools

alepha init registers the devtools plugin in alepha.config.ts and adds @alepha/devtools to devDependencies, so yarn dev gives you the inspection UI straight away — a floating cog at the bottom-left, or /__devtools/ directly. It covers atoms, modules, database contents, configuration and logs.

It is dev-only (a Vite plugin that lazy-loads the UI), so it adds nothing to a production build.

npx alepha init --no-devtools   # leave it out entirely

Workspace packages never get it — a library has no dev server for it to attach to. To keep the route but drop the floating button, pass devtools({ hideButton: true }) in your config. Removing the dependency later turns the plugin into a no-op with a warning rather than breaking config load.

Building an API-only service? Delete src/web/, src/main.browser.ts and src/main.css, and drop the WebModule line from main.server.ts. Expo projects skip the web scaffolding automatically.

#Entry Points

File Purpose
main.server.ts Server entry point
main.browser.ts Browser entry point

#Scaling with Modules

As your project grows, group features into modules:

bash
src/
  api/
    users/
      controllers/
      services/
      entities/
      index.ts           # UsersModule
    payments/
      controllers/
      services/
      entities/
      index.ts           # PaymentsModule
  web/
    app/
      AppRouter.ts
    components/
  main.server.ts
  main.browser.ts

#Naming Conventions

Directory Contains Example files
controllers/ API endpoints with $action UserController.ts
services/ Business logic UserService.ts
entities/ Database schemas with $entity userEntity.ts
providers/ External service wrappers StripeProvider.ts
schemas/ Shared Zod schemas userSchema.ts
atoms/ State definitions with $atom currentUserAtom.ts
components/ React components UserCard.tsx