Registering a user and login I have these following controller functions for registering a user and login, in my app, and I want to make it more clean and maintainable. 

Probably by using async/await and exec().  Also, the validations do not look not good. It would be great if you suggested me good practices to refactor this.

   registerUser: (req, res) =&gt; {
        const { username, email, password } = req.body
        User.create(req.body, (err, createdUser) =&gt; {
            if (err) {
                return res.status(500).json({ error: "Server error occurred" })
            } else if (!username || !email || !password) {
                return res.status(400).json({ message: "Username, email and password are must" })
            } else if (!validator.isEmail(email)) {
                return res.status(400).json({ message: "Invaid email" })
            } else if (password.length &lt; 6) {
                return res.status(400).json({ message: "Password should be of at least 6 characters" })
            }
            else {
                return res.status(200).json({ user: createdUser })
            }
        })
    },

    loginUser: async (req, res, next) =&gt; {
        const { email, password } = req.body

        if (!email || !password) {
            return res.status(400).json({ message: "Email and password are must" })
        }

        await User.findOne({ email }, (err, user) =&gt; {
            if (err) {
                return next(err)
            } else if (!validator.isEmail(email)) { 
                return res.status(400).json({ message: "Invalid email" })
            } else if (!user) {
                return res.status(402).json({ error: "User not found" })
            } else if (!user.confirmPassword(password)) {
                return res.status(402).json({ error: "incorrect password" })
            } 

        })
    }
```
Regarding your validations - extract each of your validations in validation object.
You can do something like:

class Validator {

isValid(obj) {
//return false if obj is not valid
}

message(obj) {
//return error object if obj is not valid
}

status() {
//error status if validation fails
}

}


Then you can have like EmailValidator, Required, etc. implementation, which validates email strings, etc.
You then just iterate through all current validators and if any of them fails to validate, you use it's error message and status to return error object. That way you can easily configure this by editing current validator list and reuse them in different parts of code.