Skip to main content
Version: Next

Wasp Spec (main.wasp.ts)

You define and configure the high level of your app (pages, routes, queries, actions, auth, ...) in a main.wasp.ts file in the root of your project. We call this file the Wasp Spec.

You write the Wasp Spec in TypeScript, so you get out-of-the-box support in all editors, full type checking, and the flexibility of a real programming language while configuring your app.

Coming from an older version of Wasp?

The Wasp Spec replaces two older ways of configuring a Wasp app:

A quick example

main.wasp.ts
import { app, page, route, query } from '@wasp.sh/spec'
import MainPage from './src/MainPage' with { type: "ref" }
import { getTasks } from './src/queries' with { type: "ref" }

export default app({
name: 'todoApp',
title: 'ToDo App',
wasp: { version: '^0.24.0' },
parts: [
route('MainRoute', '/', page(MainPage, { authRequired: true })),
query(getTasks, { entities: ['Task'] }),
],
})

You build your app by:

  1. Importing the building blocks (app, page, route, query, ...) from @wasp.sh/spec.
  2. Importing your own components and functions adding the import attribute with { type: "ref" }.
  3. Calling app({ ... }) with your app's configuration, listing all the pages, routes, queries, actions, etc. in the parts array.
  4. Exporting the result as the default export of the file.

wasp install

The @wasp.sh/spec package doesn't exist on npm, but it is generated by Wasp per project, so we can customize it to fit the needs of your app. We do this through the wasp install command, which sets up the necessary files and dependencies. You'll have to run it at least once after creating a new Wasp project, but you might also need to run it again later on when the generated spec needs to be updated.

If 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.

Referencing your app's code

Anywhere the Wasp Spec expects your app's function or component (like a page's component or a query's fn), you can provide it in one of two ways:

Reference imports

Recommended

Import the value with the regular syntax, adding with { type: "ref" }. Then you can pass it directly.

import MainPage from './src/MainPage' with { type: "ref" }
import { getTasks } from './src/queries' with { type: "ref" }

export default app({
parts: [
page(MainPage),
query(getTasks)
]
})

You can use relative import paths when splitting an app into multiple files:

src/auth/auth.wasp.ts
import LoginPage from './LoginPage' with { type: "ref" }

export const auth = [
page(LoginPage),
]
Limitations

Reference imports have some limitations:

  • They only work from *.wasp.ts files.
  • The referenced files must be inside the src directory.

The vast majority of Wasp apps won't run into these limitations, so we recommend using reference imports by default.

Reference objects

Just pass an object with import (or importDefault) and from:

export default app({
parts: [
page({ importDefault: 'MainPage', from: '@src/MainPage' }),
query({ import: 'getTasks', from: '@src/queries' }),
// You can rename a named import with `alias`:
query({ import: 'getTasks', alias: 'getAllTasks', from: '@src/queries' })
]
})

The from path should always start with @src and is relative to your project's src directory.

Useful patterns

Splitting your spec into multiple files

For larger apps you don't have to keep everything in main.wasp.ts. You can move related parts into their own *.wasp.ts files and combine them in main.wasp.ts.

A feature file exports an array of parts:

src/auth/auth.wasp.ts
import { page, route, Part } from '@wasp.sh/spec'

import LoginPage from './LoginPage' with { type: "ref" }
import SignupPage from './SignupPage' with { type: "ref" }

export const auth: Part[] = [
route('SignupRoute', '/signup', page(SignupPage)),
route('LoginRoute', '/login', page(LoginPage)),
]

Then main.wasp.ts imports it and spreads it into parts:

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

import MainPage from './src/MainPage' with { type: "ref" }
import { auth } from './src/auth/auth.wasp'

export default app({
name: 'todoApp',
title: 'ToDo App',
wasp: { version: '^0.24.0' },
parts: [
route('MainRoute', '/', page(MainPage, { authRequired: true })),
...auth,
],
})

All spec files should have the .wasp.ts extension, so they are included in the tsconfig.wasp.json and type-checked.

Detecting production mode

Wasp sets the NODE_ENV environment variable based on which command you use to run Wasp:

  • "development" during wasp start (and some other commands that compile the project, like wasp db migrate-dev).
  • "production" during wasp build.

Because the Wasp Spec is just TypeScript, you can read this variable to switch config values per environment:

main.wasp.ts
const isProd = process.env.NODE_ENV === 'production'

export default app({
//...
emailSender: {
provider: isProd ? 'SMTP' : 'Dummy',
defaultFrom: { email: 'hi@example.com' },
}
})

Reference

Visit our API Reference for a complete overview of all the available configuration options in the Wasp Spec.