#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:
- Node.js 22+ (recommended for beginners)
- Bun 1.3+
#Create a Project
npx alepha@latest init my-app
This creates a my-app directory with:
package.jsonwith Alepha as a dependencytsconfig.jsonconfigured for TypeScriptalepha.config.tswith documented build optionsbiome.jsonfor formatting and lintingsrc/api/with an example controllersrc/web/with a React router and pagesrc/main.server.tsandsrc/main.browser.tsas 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:
cd my-app
Open the entry file. It wires up the two generated modules:
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:
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:
[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:
- Hot Module Replacement (HMR) -- change code, server updates instantly.
- TypeScript support -- no build step required.
- 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.
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
$actionpaths are automatically prefixed with/api. This endpoint serves atGET /api/hello. - The
schema.responsevalidates the return value and generates OpenAPI documentation. - If a
schema.bodyis provided, the method defaults toPOST. - 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:
node dist
Or with Bun:
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_PORTenvironment 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:
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:
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:
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:
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 |