Migration from 0.11.X to 0.12.X
To fully migrate from 0.11.X to the latest version of Wasp, you should first migrate to 0.12.X and then continue going through the migration guides.
Make sure to read the migration guide from 0.12.X to 0.13.X after you finish this one.
What's new in Wasp 0.12.0?
New project structure
Here's a file tree of a fresh Wasp project created with the previous version of Wasp.
More precisely, this is what you'll get if you run wasp new myProject
using Wasp 0.11.x:
.
├── .gitignore
├── main.wasp
├── src
│ ├── client
│ │ ├── Main.css
│ │ ├── MainPage.jsx
│ │ ├── react-app-env.d.ts
│ │ ├── tsconfig.json
│ │ └── waspLogo.png
│ ├── server
│ │ └── tsconfig.json
│ ├── shared
│ │ └── tsconfig.json
│ └── .waspignore
└── .wasproot
Compare that with the file tree of a fresh Wasp project created with Wasp
0.12.0. In other words, this is what you will get by running wasp new myProject
from this point onwards:
.
├── .gitignore
├── main.wasp
├── package.json
├── public
│ └── .gitkeep
├── src
│ ├── Main.css
│ ├── MainPage.jsx
│ ├── queries.ts
│ ├── vite-env.d.ts
│ ├── .waspignore
│ └── waspLogo.png
├── tsconfig.json
├── vite.config.ts
└── .wasproot
The main differences are:
- The server/client code separation is no longer necessary. You can now organize
your code however you want, as long as it's inside the
src
directory. - All external imports in your Wasp file must have paths starting with
@src
(e.g.,import foo from '@src/bar.js'
) where@src
refers to thesrc
directory in your project root. The paths can no longer start with@server
or@client
. - Your project now features a top-level
public
dir. Wasp will publicly serve all the files it finds in this directory. Read more about it here.
Our Overview docs explain the new structure in detail, while this page provides a quick guide for migrating existing projects.
New auth
In Wasp 0.11.X, authentication was based on the User
model which the developer needed to set up properly and take care of the auth fields like email
or password
.
app myApp {
wasp: {
version: "^0.11.0"
},
title: "My App",
auth: {
userEntity: User,
externalAuthEntity: SocialLogin,
methods: {
gitHub: {}
},
onAuthFailedRedirectTo: "/login"
},
}
entity User {=psl
id Int @id @default(autoincrement())
username String @unique
password String
externalAuthAssociations SocialLogin[]
psl=}
entity SocialLogin {=psl
id Int @id @default(autoincrement())
provider String
providerId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int
createdAt DateTime @default(now())
@@unique([provider, providerId, userId])
psl=}
From 0.12.X onwards, authentication is based on the auth models which are automatically set up by Wasp. You don't need to take care of the auth fields anymore.
The User
model is now just a business logic model and you use it for storing the data that is relevant for your app.
app myApp {
wasp: {
version: "^0.12.0"
},
title: "My App",
auth: {
userEntity: User,
methods: {
gitHub: {}
},
onAuthFailedRedirectTo: "/login"
},
}
entity User {=psl
id Int @id @default(autoincrement())
psl=}
With our old auth implementation, if you were using both Google and email auth methods, your users could sign up with Google first and then, later on, reset their password and therefore also enable logging in with their email and password. This was the only way in which a single user could have multiple login methods at the same time (Google and email).
This is not possible anymore. The new auth system doesn't support multiple login methods per user at the moment. We do plan to add this soon though, with the introduction of the account merging feature.
If you have any users that have both Google and email login credentials at the same time, you will have to pick only one of those for that user to keep when migrating them.
_waspCustomValidations
is deprecatedAuth field customization is no longer possible using the _waspCustomValidations
on the User
entity. This is a part of auth refactoring that we are doing to make it easier to customize auth. We will be adding more customization options in the future.
You can read more about the new auth system in the Accessing User Data section.
How to Migrate?
These instructions are for migrating your app from Wasp 0.11.X
to Wasp 0.12.X
, meaning they will work for all minor releases that fit this pattern (e.g., the guide applies to 0.12.0
, 0.12.1
, ...).
The guide consists of two big steps:
- Migrating your Wasp project to the new structure.
- Migrating to the new auth.
If you get stuck at any point, don't hesitate to ask for help on our Discord server.
Migrating Your Project to the New Structure
You can easily migrate your old Wasp project to the new structure by following a
series of steps. Assuming you have a project called foo
inside the
directory foo
, you should:
- Install the
0.12.x
version of Wasp.curl -sSL https://get.wasp.sh/installer.sh | sh -s -- -v 0.12.4
- Make sure to backup or save your project before starting the procedure (e.g., by committing it to source control or creating a copy).
- Position yourself in the terminal in the directory that is a parent of your wasp project directory (so one level above: if you do
ls
, you should see your wasp project dir listed). - Run the migration script (replace
foo
at the end with the name of your Wasp project directory) and follow the instructions:npx wasp-migrate foo
In case the migration script doesn't work well for you, you can do the same steps manually, as described here:
That's it! You now have a properly structured Wasp 0.12.0 project in the foo
directory.
Your app probably doesn't quite work yet due to some other changes in Wasp 0.12.0, but we'll get to that in the next sections.
Migrating declaration names
Wasp 0.12.0 adds a casing constraints when naming Queries, Actions, Jobs, and Entities in the main.wasp
file.
The following casing conventions have now become mandatory:
- Operation (i.e., Query and Action) names must begin with a lowercase letter:
query getTasks {...}
,action createTask {...}
. - Job names must begin with a lowercase letter:
job sendReport {...}
. - Entity names must start with an uppercase letter:
entity Task {...}
.
Migrating the Tailwind Setup
If you don't use Tailwind in your project, you can skip this section.
There is a small change in how the tailwind.config.cjs
needs to be defined in Wasp 0.12.0.
You'll need to wrap all your paths in the content
field with the resolveProjectPath
function. This makes sure that the paths are resolved correctly when generating your CSS.
Here's how you can do it:
- Before
- After
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
const { resolveProjectPath } = require('wasp/dev')
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
resolveProjectPath('./src/**/*.{js,jsx,ts,tsx}'),
],
theme: {
extend: {},
},
plugins: [],
}
Default Server Dockerfile Changed
If you didn't customize your Dockerfile or had a custom build process for the Wasp server, you can skip this section.
Between Wasp 0.11.X and 0.12.X, the Dockerfile that Wasp generates for you for deploying the server has changed. If you defined a custom Dockerfile in your project root dir or in any other way relied on its contents, you'll need to update it to incorporate the changes that Wasp 0.12.X made.
We suggest that you temporarily move your custom Dockerfile to a different location, then run wasp start
to generate the new Dockerfile.
Check out the .wasp/out/Dockerfile
to see the new Dockerfile and what changes you need to make. You'll probably need to copy some of the changes from the new Dockerfile to your custom one to make your app work with Wasp 0.12.X.
Migrating to the New Auth
As shown in the previous section, Wasp significantly changed how authentication works in version 0.12.0. This section leads you through migrating your app from Wasp 0.11.X to Wasp 0.12.X.
Migrating your existing app to the new auth system is a two-step process:
- Migrate to the new auth system
- Clean up the old auth system
While going through these steps, we will focus first on doing the changes locally (including your local development database).
Once we confirm everything works well locally, we will apply the same changes to the deployed app (including your production database).
We'll put extra info for migrating a deployed app in a box like this one.
1. Migrate to the New Auth System
You can follow these steps to migrate to the new auth system (assuming you already migrated the project structure to 0.12, as described above):
Migrate
getUserFields
and/oradditionalSignupFields
in themain.wasp
file to the newuserSignupFields
field.If you are not using them, you can skip this step.
In Wasp 0.11.X, you could define a
getUserFieldsFn
to specify extra fields that would get saved to theUser
when using Google or GitHub to sign up.You could also define
additionalSignupFields
to specify extra fields for the Email or Username & Password signup.In 0.12.X, we unified these two concepts into the
userSignupFields
field.Migration for Email and Username & Password
Remove the
auth.methods.email.allowUnverifiedLogin
field from yourmain.wasp
file.In Wasp 0.12.X we removed the
auth.methods.email.allowUnverifiedLogin
field to make our Email auth implementation easier to reason about. If you were using it, you should remove it from yourmain.wasp
file.Ensure your local development database is running.
Do the schema migration (create the new auth tables in the database) by running:
wasp db migrate-dev
You should see the new
Auth
,AuthIdentity
andSession
tables in your database. You can use thewasp db studio
command to open the database in a GUI and verify the tables are there. At the moment, they will be empty.Do the data migration (move existing users from the old auth system to the new one by filling the new auth tables in the database with their data):
Implement your data migration function(s) in e.g.
src/migrateToNewAuth.ts
.Below we prepared examples of migration functions for each of the auth methods, for you to use as a starting point. They should be fine to use as-is, meaning you can just copy them and they are likely to work out of the box for typical use cases, but you can also modify them for your needs.
We recommend you create one function per each auth method that you use in your app.
Define custom API endpoints for each migration function you implemented.
With each data migration function below, we provided a relevant
api
declaration that you should add to yourmain.wasp
file.Run the data migration function(s) on the local development database by calling the API endpoints you defined in the previous step.
You can call the endpoint by visiting the URL in your browser, or by using a tool like
curl
or Postman.For example, if you defined the API endpoint at
/migrate-username-and-password
, you can call it by visitinghttp://localhost:3001/migrate-username-and-password
in your browser.This should be it, you can now run
wasp db studio
again and verify that there is now relevant data in the new auth tables (Auth
andAuthIdentity
;Session
should still be empty for now).
Verify that the basic auth functionality works by running
wasp start
and successfully signing up / logging in with each of the auth methods.Update your JS/TS code to work correctly with the new auth.
You might want to use the new auth helper functions to get the
email
orusername
from a user object. For example,user.username
might not work anymore for you, since theusername
obtained by the Username & Password auth method isn't stored on theUser
entity anymore (unless you are explicitly storing something intouser.username
, e.g. viauserSignupFields
for a social auth method like Github). Same goes foremail
from Email auth method.Instead, you can now use
getUsername(user)
to get the username obtained from Username & Password auth method, orgetEmail(user)
to get the email obtained from Email auth method.Read more about the helpers in the Accessing User Data section.
Finally, check that your app now fully works as it worked before. If all the above steps were done correctly, everything should be working now.
Migrating a deployed appAfter successfully performing migration locally so far, and verifying that your app works as expected, it is time to also migrate our deployed app.
Before migrating your production (deployed) app, we advise you to back up your production database in case something goes wrong. Also, besides testing it in development, it's good to test the migration in a staging environment if you have one.
We will perform the production migration in 2 steps:
- Deploying the new code to production (client and server).
- Migrating the production database data.
Between these two steps, so after successfully deploying the new code to production and before migrating the production database data, your app will not be working completely: new users will be able to sign up, but existing users won't be able to log in, and already logged in users will be logged out. Once you do the second step, migrating the production database data, it will all be back to normal. You will likely want to keep the time between the two steps as short as you can.
First step: deploy the new code (client and server), either via
wasp deploy
(i.e.wasp deploy fly deploy
) or manually.Check our Deployment docs for more details.
Second step: run the data migration functions on the production database.
You can do this by calling the API endpoints you defined in the previous step, just like you did locally. You can call the endpoint by visiting the URL in your browser, or by using a tool like
curl
or Postman.For example, if you defined the API endpoint at
/migrate-username-and-password
, you can call it by visitinghttps://your-server-url.com/migrate-username-and-password
in your browser.
Your deployed app should be working normally now, with the new auth system.
2. Cleanup the Old Auth System
Your app should be working correctly and using new auth, but to finish the migration, we need to clean up the old auth system:
In
main.wasp
file, delete auth-related fields from theUser
entity, since with 0.12 they got moved to the internal Wasp entityAuthIdentity
.- This means any fields that were required by Wasp for authentication, like
email
,password
,isEmailVerified
,emailVerificationSentAt
,passwordResetSentAt
,username
, etc. - There are situations in which you might want to keep some of them, e.g.
email
and/orusername
, if they are still relevant for you due to your custom logic (e.g. you are populating them withuserSignupFields
upon social signup in order to have this info easily available on theUser
entity). Note that they won't be used by Wasp Auth anymore, they are here just for your business logic.
- This means any fields that were required by Wasp for authentication, like
In
main.wasp
file, remove theexternalAuthEntity
field from theapp.auth
and also remove the wholeSocialLogin
entity if you used Google or GitHub auth.Delete the data migration function(s) you implemented earlier (e.g. in
src/migrateToNewAuth.ts
) and also the corresponding API endpoints from themain.wasp
file.Run
wasp db migrate-dev
again to apply these changes and remove the redundant fields from the database.
After doing the steps above successfully locally and making sure everything is working, it is time to push these changes to the deployed app again.
Deploy the app again, either via wasp deploy
or manually. Check our Deployment docs for more details.
The database migrations will automatically run on successful deployment of the server and delete the now redundant auth-related User
columns from the database.
Your app is now fully migrated to the new auth system.
Next Steps
If you made it this far, you've completed all the necessary steps to get your Wasp app working with Wasp 0.12.x. Nice work!
Finally, since Wasp no longer requires you to separate your client source files
(previously in src/client
) from server source files (previously in
src/server
), you are now free to reorganize your project however you think is best,
as long as you keep all the source files in the src/
directory.
This section is optional, but if you didn't like the server/client separation, now's the perfect time to change it.
For example, if your src
dir looked like this:
src
│
├── client
│ ├── Dashboard.tsx
│ ├── Login.tsx
│ ├── MainPage.tsx
│ ├── Register.tsx
│ ├── Task.css
│ ├── TaskLisk.tsx
│ ├── Task.tsx
│ └── User.tsx
├── server
│ ├── taskActions.ts
│ ├── taskQueries.ts
│ ├── userActions.ts
│ └── userQueries.ts
└── shared
└── utils.ts
you can now change it to a feature-based structure (which we recommend for any project that is not very small):
src
│
├── task
│ ├── actions.ts -- former taskActions.ts
│ ├── queries.ts -- former taskQueries.ts
│ ├── Task.css
│ ├── TaskLisk.tsx
│ └── Task.tsx
├── user
│ ├── actions.ts -- former userActions.ts
│ ├── Dashboard.tsx
│ ├── Login.tsx
│ ├── queries.ts -- former userQueries.ts
│ ├── Register.tsx
│ └── User.tsx
├── MainPage.tsx
└── utils.ts
Appendix
Example Data Migration Functions
The migration functions provided below are written with the typical use cases in mind and you can use them as-is. If your setup requires additional logic, you can use them as a good starting point and modify them to your needs.
Note that all of the functions below are written to be idempotent, meaning that running a function multiple times can't hurt. This allows executing a function again in case only a part of the previous execution succeeded and also means that accidentally running it one time too much won't have any negative effects. We recommend you keep your data migration functions idempotent.
Username & Password
To successfully migrate the users using the Username & Password auth method, you will need to do two things:
Migrate the user data
Username & Password data migration function
Provide a way for users to migrate their password
There is a breaking change between the old and the new auth in the way the password is hashed. This means that users will need to migrate their password after the migration, as the old password will no longer work.
Since the only way users using username and password as a login method can verify their identity is by providing both their username and password (there is no email or any other info, unless you asked for it and stored it explicitly), we need to provide them a way to exchange their old password for a new password. One way to handle this is to inform them about the need to migrate their password (on the login page) and provide a custom page to migrate the password.
Steps to create a custom page for migrating the password
Email
To successfully migrate the users using the Email auth method, you will need to do two things:
Migrate the user data
Email data migration function
Ask the users to reset their password
There is a breaking change between the old and the new auth in the way the password is hashed. This means that users will need to reset their password after the migration, as the old password will no longer work.
It would be best to notify your users about this change and put a notice on your login page to request a password reset.