TL;DR
Wasp is an open-source framework that uses a simple DSL to generate a full-stack React + Node.js app — complete with auth, database, email, cron jobs, and deployment. Write 10 lines of config, get 1000 lines of boilerplate for free.
What Is Wasp?
Wasp is a Rails-like framework for JavaScript:
- Full-stack DSL — declare routes, auth, entities in simple config
- React + Node.js — generates production-ready code
- Built-in auth — email/password, Google, GitHub, Discord
- Prisma ORM — type-safe database access
- Type-safe RPC — auto-generated API with full TypeScript
- Jobs and cron — background tasks built-in
- One-command deploy — Fly.io or Railway
- Free — MIT license
Quick Start
curl -sSL https://get.wasp-lang.dev/installer.sh | sh
wasp new my-app
cd my-app
wasp start
The Wasp Config
// main.wasp — this is ALL you need for a full-stack app
app MyApp {
wasp: { version: "^0.15.0" },
title: "My SaaS App",
auth: {
userEntity: User,
methods: {
email: {},
google: {},
gitHub: {},
},
onAuthFailedRedirectTo: "/login",
},
db: { system: PostgreSQL },
emailSender: {
provider: Resend,
},
}
// Database entities
entity User {=psl
id Int @id @default(autoincrement())
tasks Task[]
psl=}
entity Task {=psl
id Int @id @default(autoincrement())
description String
isDone Boolean @default(false)
user User @relation(fields: [userId], references: [id])
userId Int
psl=}
// Pages
route HomeRoute { path: "/", to: HomePage }
page HomePage {
authRequired: true,
component: import { HomePage } from "@src/pages/Home"
}
route LoginRoute { path: "/login", to: LoginPage }
page LoginPage {
component: import { LoginPage } from "@src/pages/Login"
}
// Operations (type-safe API)
query getTasks {
fn: import { getTasks } from "@src/queries",
entities: [Task],
}
action createTask {
fn: import { createTask } from "@src/actions",
entities: [Task],
}
// Cron job
job dailyReport {
executor: PgBoss,
perform: {
fn: import { sendReport } from "@src/jobs/report"
},
schedule: {
cron: "0 9 * * *"
},
}
React Pages
// src/pages/Home.tsx
import { useQuery } from "wasp/client/operations";
import { getTasks, createTask } from "wasp/client/operations";
export function HomePage() {
const { data: tasks, isLoading } = useQuery(getTasks);
const handleAdd = async () => {
await createTask({ description: "New task" });
};
if (isLoading) return <div>Loading...</div>;
return (
<div>
<h1>My Tasks</h1>
<button onClick={handleAdd}>Add Task</button>
{tasks?.map((task) => (
<div key={task.id}>
{task.isDone ? "Done" : "Todo"}: {task.description}
</div>
))}
</div>
);
}
Server Operations
// src/queries.ts
import { type GetTasks } from "wasp/server/operations";
export const getTasks: GetTasks<void, Task[]> = async (args, context) => {
return context.entities.Task.findMany({
where: { userId: context.user.id },
orderBy: { id: "desc" },
});
};
// src/actions.ts
import { type CreateTask } from "wasp/server/operations";
export const createTask: CreateTask<{ description: string }, Task> = async (
{ description },
context
) => {
return context.entities.Task.create({
data: {
description,
userId: context.user.id,
},
});
};
Deploy
# Deploy to Fly.io
wasp deploy fly setup my-app mia
wasp deploy fly cmd secrets set DATABASE_URL=...
wasp deploy fly deploy
# Or deploy to Railway
wasp deploy
Wasp vs Alternatives
| Feature | Wasp | Next.js | Remix | RedwoodJS |
|---|---|---|---|---|
| Auth built-in | Yes | No (NextAuth) | No | Yes |
| Database | Prisma built-in | Manual | Manual | Prisma |
| Type-safe RPC | Auto-generated | tRPC manual | Manual | Auto-generated |
| Cron jobs | Built-in | Manual | Manual | Manual |
| Built-in | Manual | Manual | Manual | |
| Boilerplate | Minimal (DSL) | Moderate | Moderate | Moderate |
| Deploy | One command | Manual | Manual | Manual |
Resources
- Wasp Documentation
- GitHub Repository — 14K+ stars
- SaaS Template — production SaaS starter
- Examples
Building a SaaS that processes web data? My Apify tools extract data from any website — build your data product with Wasp in record time. Questions? Email spinov001@gmail.com
Top comments (0)