Skip to main content
Version: Next
note

Last checked with Wasp 0.24.

This guide depends on external libraries or services, so it may become outdated over time. We do our best to keep it up to date, but make sure to check their documentation for any changes.

Migrating from the Wasp DSL

Wasp used to have its own configuration language, the Wasp DSL, which you wrote in a main.wasp file. Start with Wasp 0.24, the Wasp DSL is now retired in favor of the Wasp Spec: a main.wasp.ts file written in TypeScript.

Let an LLM do the heavy lifting

The mapping below is mechanical. You can give the Wasp Spec reference and your main.wasp to the LLM of your choice and ask it to rewrite it following that reference. We had great results with this.

New features

Just TypeScript

The Wasp DSL was a custom language, so it needed its own IDE extension for highlighting and autocompletion, and you couldn't use the JavaScript ecosystem inside it. The Wasp Spec is just TypeScript, so:

  • No special IDE extension is needed. You get type checking, autocompletion, and go-to-definition from your editor's regular TypeScript support.
  • You can import and use npm packages, environment variables, and your own helpers while building the config.
  • You can use normal language features (variables, functions, loops, conditionals) to remove repetition from your config.

Multiple files

The Wasp DSL kept your entire configuration in a single main.wasp. The Wasp Spec lets you split it across multiple *.wasp.ts files and import parts between them, so you can keep large configs organized (for example, a separate auth.wasp.ts or payments.wasp.ts next to the feature it configures).

See the Wasp Spec documentation for details.

Changes

Overview

WhatBeforeAfter
File namemain.waspmain.wasp.ts
Creating an appapp Name { ... }app({ name, ..., parts: [] })
Configuring the app
app Name {
auth: { ... },
server: { ... },
}
app({
auth: ...,
server: ...,
})
Adding app declarations
route X { ... }
query X { ... }
action X { ... }
app({
parts: [
route(...),
query(...),
action(...),
]
})
Referencing codeimport { x } from "@src/..." inside a declarationimport { ... } from "./src/..." with { type: "ref" } at the top level
Entity referencesTask (identifier)'Task' (string)

App, routes, and pages

In the DSL, a route points to a page by name. In the Wasp Spec, route takes the page object directly.

main.wasp
app todoApp {
title: "ToDo App",
wasp: { version: "^0.24.0" }
}

route MainRoute { path: "/", to: MainPage }
page MainPage {
component: import { MainPage } from "@src/MainPage",
authRequired: true
}

Note that route no longer references a page by name (to: MainPage); it takes the page(...) object directly.

Queries and actions

main.wasp
query getTasks {
fn: import { getTasks } from "@src/queries",
entities: [Task]
}

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

APIs: httpRoute becomes positional arguments

The DSL's httpRoute: (GET, "/path") becomes the first two arguments of api.

main.wasp
apiNamespace bar {
middlewareConfigFn: import { barNamespaceMiddlewareFn } from "@src/apis",
path: "/bar"
}

api barBaz {
fn: import { barBaz } from "@src/apis",
auth: false,
entities: [Task],
httpRoute: (GET, "/bar/baz")
}

Jobs: perform is flattened

The DSL's perform: { fn, executorOptions } is flattened: fn becomes the first argument and executorOptions becomes performExecutorOptions.

main.wasp
job mySpecialJob {
executor: PgBoss,
perform: {
fn: import { foo } from "@src/jobs/bar",
executorOptions: { pgBoss: {=json { "retryLimit": 1 } json=} }
},
entities: [Task]
}

CRUD

main.wasp
crud tasks {
entity: Task,
operations: {
getAll: {},
create: { overrideFn: import { createTask } from "@src/actions" }
}
}

Top-level config: auth, server, client, db, emailSender, webSocket

These were top-level fields of the app declaration's dictionary in the DSL. In the Wasp Spec they are keys of the app({ ... }) object.

main.wasp
app todoApp {
title: "ToDo App",
wasp: { version: "^0.24.0" },
auth: {
userEntity: User,
methods: { google: {} },
onAuthFailedRedirectTo: "/login"
},
client: {
rootComponent: import App from "@src/App"
},
emailSender: {
provider: SMTP,
defaultFrom: { email: "hi@example.com" }
}
}

How to migrate

These steps assume your project is already on Wasp ^0.24.0. If it isn't, follow the migration guide first.

Wasp validates the Wasp Spec support files during migration, including the required package.json entries, tsconfig.wasp.json options, and tsconfig.src.json exclusions.

  1. Rename tsconfig.json to tsconfig.src.json and make it exclude Wasp Spec files:

    tsconfig.src.json
    {
    // ...
    "include": ["src"],
    "exclude": ["**/*.wasp.ts"]
    }
  2. Create a new tsconfig.json that references the other two configs:

    tsconfig.json
    {
    "files": [],
    "references": [
    { "path": "./tsconfig.src.json" },
    { "path": "./tsconfig.wasp.json" }
    ]
    }
  3. Create a tsconfig.wasp.json with the required compiler options and the Wasp Spec includes:

    tsconfig.wasp.json
    {
    "compilerOptions": {
    "target": "ES2022",
    "module": "esnext",
    "moduleResolution": "bundler",
    "jsx": "preserve",
    "strict": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "skipLibCheck": true,
    "allowJs": true,
    "noEmit": true,
    "lib": ["ES2023"]
    },
    "include": ["main.wasp.ts", "**/*.wasp.ts"]
    }
  4. Add the required devDependencies to your package.json:

    package.json
    {
    "devDependencies": {
    "@types/node": "^24.0.0",
    "@wasp.sh/spec": "file:.wasp/spec"
    }
    }

    Keep your existing dependencies, and add these entries. @types/node is required because the Wasp Spec runs in a Node.js environment, and @wasp.sh/spec provides the local Wasp Spec API package.

  5. Run wasp install.

  6. Rename main.wasp to main.wasp.old.

  7. Create a main.wasp.ts file with the following content:

    main.wasp.ts
    import { app } from '@wasp.sh/spec'

    export default app({
    name: "myAppName",
    parts: []
    })
  8. Rewrite your config:

    You can use the mapping above. Top-level concerns (e.g. auth, server, client, db, emailSender, webSocket) become keys of the app({ ... }) object; pages, routes, queries, actions, APIs, jobs, and CRUDs go into the parts array.

  9. Run your app with wasp start. If everything is correct, your app should behave exactly as before.

note

At some points, when the Spec needs to be regenerated, Wasp will tell you to run wasp install before being able to start the app. Usually, this might happen when upgrading Wasp versions, running wasp clean, or removing the node_modules folder.

  1. Delete main.wasp.old once you're sure the new config works.

See the full Wasp Spec reference for every option. Got stuck? Reach out on our Discord and we'll help.