When working on multiple projects, I try to save as much time as I can and move as fast as possible without getting stuck. I'd rather spend time writing logic and moving the product forward than fighting the frameworks that I use. The following are the tools and techniques I've been using and they're working really well for me. It's completely changed the way I used to do web development. It's a simple setup, it's flexible enough to scale with the needs of the application, and developing with this setup allows me to ship fast.
Next.js FTW
God, I love Next.js! It just brings the best parts of building web applications all in one easy-to-use package. I started using Next.js early last year. I loved how easy it was to start coding a React application with zero configuration. I used it only for the front-end at first. Coming from writing back-end with Express.js, API routes felt a little weird to me.
Even when I started using it, I missed a lot of things that were available to Express.js but can't be used in Next.js. This is when I found an amazing package called next-connect
which lets you use connect-style middleware in Next.js. More on that later.
I've been using Next.js exclusively for the past few months. As a React developer, Next.js is all we need to build full-stack web applications.
Next.js API Routes with next-connect
Normally when we write API routes in Next.js, we export a handler
function with conditional blocks to handle different methods.
export default function handler(req, res) {
if (req.method === 'GET') {
...
} else if (req.method === 'POST') {
...
}
}
Enter next-connect
. It's an npm package that lets us write expressjs-style routes and use connect-style middleware.
import nc from 'next-connect';
...
const users = async(req, res) => {
// Fetch a list of users
...
}
const user = async(req, res) => {
// Create a new user
...
}
export default nc({ attachParams: true })
.get(users)
.post(user);
Using middleware with next-connect
Like I previously mentioned, next-connect
lets us use connect-style middleware. This means any middleware that we use with expressjs can be used in Next.js API routes. We can also write custom middleware.
Let's see an example with a commonly used expressjs middleware, cors
:
import nc from 'next-connect';
import Cors from 'cors';
...
export default nc({ attachParams: true })
.use(Cors({ origin: true })) // all valid cors middleware options apply here
.get(users)
.post(user);
Connecting to MongoDB
My database of choice, for the time being, is MongoDB. I usually host an instance on AWS EC2 but MongoDB Atlas is a good choice as well. Connecting to a MongoDB instance from Next.js is a little different from the traditional method.
When deployed, API routes become isolated serverless functions. They're stateless and asynchronous. This is done so that they can be scaled independently. What this means is that we can't use traditional database connection methods.
If you're using Vercel for deploying your application and there's a built-in integration for the database of your choice, you should use it. As of this writing, MongoDB integration is in development. But relational databases that support serverless — PlanetScale, FaunaDB, and Supabase — are already available. MongoDB Realm has serverless support as well, but I haven't used it.
Next.js has an example code for using MongoDB which has worked well.
Moving fast on the front-end
With the backend sorted, the next step to figure out how to move fast is the frontend. Here there are several options we could go with.
For the past year, I've been using Ant Design and TailwindCSS for building UI components. Ant Design has a comprehensive set of components, variations for each component, good examples, and documentation. For custom styling, I used TailwindCSS.
It was great but I ran into difficulties with this combination. Styling Ant Design components, especially when it's a nested div that you want to slightly modify is not possible without writing custom CSS, targeting each nested div or span.
After some exploration, I found ChakraUI. It's not as comprehensive as Ant Design but it has almost all the components that we would normally need. It also comes with built-in hooks that come in handy when building UI. The part I love most about ChakraUI is that it's extremely easy to make dark mode work in our applications. I found that applying a custom theme was also quite easy.
There is a bit of a learning curve but once you start seeing the patterns, building UI becomes so easy and intuitive.
Other tools and libraries that make life easier
- ESLint: Identifies issues in the javascript and typescript files I write, enforces rules for syntax and patterns.
- Prettier: Enforces a global code-style no matter how the code is formatted while writing.
husky
+lint-staged
: Runs eslint and prettier every time I try to commit to source control. This makes sure that the code I push to Github is properly formatted and doesn't have any syntactical problems or anti-patterns. I don't write tests (gasps) but if I did, this is where we can run our tests as well.- SWR: React hooks for data fetching that is super fun to use and supercharges how we make API calls in our applications.
- Formik: Formik makes working with forms incredibly easy by keeping track of changes in values, errors, visited fields. This way, we spend a lot less time handling these things.
- Yup: Formik does not do data validation in forms. We're free to write our own, but in the interest of moving fast, I use Yup (recommended by Formik). It's fast and quite easy to use.
Emails
Most web applications send some form of transactional email — account signups, password recovery, payments, etc. I usually use nodemailer
in combination with Mailgun or SendGrid. Both those services have great SDKs and APIs for Node.js. I've found Mailgun documentation to be outdated, but their Github issues usually had a solution. AWS SES is also a great option.
Deploying the web application
This one's pretty easy. I use the Vercel platform for deploying my Next.js applications and websites. I've also used Netlify. Both are great options. Both platforms come with continuous deployment built-in that saves a ton of time. If there is something custom I require, like cron jobs, I use Github Actions.
Git-centric development is one of the coolest things to happen to continuous deployments. What required configuration with YAML files now requires zero setups. Literally. We add our project to Vercel or Netlify once, they figure out all the hooks to our source control. All we have to do is push our code to Github or wherever our code lives in the cloud.
That's my web application tech stack for the foreseeable future. I've been learning PostgreSQL in my free time so I will switch to it soon.
Building web applications in 2021 is just a blast. There is no product idea that's out of reach because the frictions from writing web applications from a decade ago are largely gone. I do face some issues from time to time, but most of them are mistakes on my part.
I hope you found something here that can help you build faster or makes writing code easy. What is your tech stack for building web applications? Are there tools you love that I haven't mentioned here? I'm always looking for better tools and libraries so I would love to hear about those. Hit me up in the comments.
Later.