Docs / Programming & Development / Deploy Wasp Full-Stack

Deploy Wasp Full-Stack

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 386 views · 3 min read

Wasp is a full-stack web framework that uses a simple DSL to describe your app, then generates a React frontend, Node.js backend, and Prisma database layer. It eliminates boilerplate while keeping full flexibility. This guide covers building and deploying Wasp applications.

Installation

# Install Wasp
curl -sSL https://get.wasp-lang.dev/installer.sh | sh

# Verify
wasp version

# Create new project
wasp new my-app
cd my-app
wasp start

The Wasp DSL

// main.wasp
app MyApp {
  wasp: { version: "^0.14.0" },
  title: "My App",
  auth: {
    userEntity: User,
    methods: {
      usernameAndPassword: {},
      google: {},
    },
    onAuthFailedRedirectTo: "/login",
  },
  db: {
    system: PostgreSQL,
  },
}

// 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)
  userId      Int
  user        User     @relation(fields: [userId], references: [id])
psl=}

// Pages and routes
route RootRoute { path: "/", to: MainPage }
page MainPage {
  authRequired: true,
  component: import { MainPage } from "@src/pages/MainPage",
}

// Operations (queries and actions)
query getTasks {
  fn: import { getTasks } from "@src/queries",
  entities: [Task],
}

action createTask {
  fn: import { createTask } from "@src/actions",
  entities: [Task],
}

Server Operations

// src/queries.ts
import { getTasks } from "wasp/server/operations";

export const getTasks = async (args, context) => {
  if (!context.user) throw new Error("Not authenticated");
  return context.entities.Task.findMany({
    where: { userId: context.user.id },
    orderBy: { id: "desc" },
  });
};

// src/actions.ts
export const createTask = async ({ description }, context) => {
  if (!context.user) throw new Error("Not authenticated");
  return context.entities.Task.create({
    data: {
      description,
      userId: context.user.id,
    },
  });
};

React Frontend

// src/pages/MainPage.tsx
import { useQuery } from "wasp/client/operations";
import { getTasks, createTask } from "wasp/client/operations";
import { useState } from "react";

export function MainPage() {
  const { data: tasks, isLoading } = useQuery(getTasks);
  const [description, setDescription] = useState("");

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    await createTask({ description });
    setDescription("");
  };

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Tasks</h1>
      <form
        <input value={description} => setDescription(e.target.value)} />
        <button type="submit">Add Task</button>
      </form>
      {tasks?.map((task) => (
        <div key={task.id}>{task.description}</div>
      ))}
    </div>
  );
}

Building for Production

# Build the project
wasp build

# Output at .wasp/build/
# Contains Dockerfile for both client and server

Deploying to VPS

# Option 1: Docker deployment
cd .wasp/build
docker build -f Dockerfile.server -t myapp-server .
docker build -f Dockerfile.client -t myapp-client .

# docker-compose.yml
services:
  server:
    image: myapp-server
    ports:
      - "3001:3001"
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/myapp
      JWT_SECRET: your-jwt-secret
      WASP_WEB_CLIENT_URL: https://myapp.example.com
    depends_on:
      - db

  client:
    image: myapp-client
    ports:
      - "3000:80"
    environment:
      REACT_APP_API_URL: https://api.myapp.example.com

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: myapp
      POSTGRES_PASSWORD: password

volumes:
  pgdata:

# Option 2: wasp deploy (to Fly.io)
wasp deploy fly launch my-app mia

Summary

Wasp dramatically reduces full-stack boilerplate by generating React, Node.js, and Prisma code from a simple DSL. Authentication, CRUD operations, and client-server communication are built in with type safety. The learning curve is minimal — write operations in plain TypeScript, connect them in the DSL, and Wasp handles the rest. For rapid prototyping and small-to-medium applications, Wasp is one of the fastest paths from idea to deployed product.

Was this article helpful?