Going ham with Next.js
Traditionally, when I'm building apps, my approach is to create an API with Node and a frontend in React or React Native, depending on whether I'm targeting web or mobile.
At the beginning of 2019, I decided to shake up my stack and learn new things. Since then, I've been adopting new tech quickly into my side projects and going for newer over comfortable ones to get some experience with them under my belt.
I started with TypeScript and GraphQL, and every side project I built afterward used both. Then I added Prisma, Next.js, TailwindCSS, and Framer Motion to projects. I love them all so much for what they bring to the table.
But even then, I was still building APIs in Node with Prisma and hosting them on Render and doing mobile with React Native and web with Next.js. I build many side projects, so my hosting bill was starting to go up considerably after Render increased their prices, and it made no sense to pay $15 per month for projects that I abandon as I move on to the next one.
So I took another look at Next.js and Vercel and realized it made the most sense to build and deploy my next generation of projects there.
I've built two things lately that I'm quite happy about, so let's get into them.
I bought the flyfly.dev domain a few months ago when I was trying to set up Flynn on a $5 DigitalOcean box to deploy my side projects there instead of $7 per app and $7 per database on Render. But after much headbanging, I gave up on it. Flynn, while promising, has poor documentation and is quite unstable. I'm still looking for a cool alternative; CapRover seems reasonable, but I'm not a fan of their UI.
While working on another project, I realized I needed to store the contact and help forms' responses somewhere. But I didn't want to put them in my database. So I looked around and found Formspree. It was brilliant. Unlike Typeform, I got to manage the look and feel of my forms and keep them on my website and still got to collect responses without adding anything to my database.
However, I wasn't happy with the UI, and in that instant, FlyFly was born.
The first version was the same architecture; API with Node and Prisma on Render and backend with Next.js on Vercel. But as I built the product, I realized I could do more and even launch it for others to use. I also wanted to keep the costs low, so I dropped the Node API and refactored everything into the Next.js app. I initially built it with Prisma, but I couldn't find a PostgreSQL provider that was cheap and sufficient. I looked around and found FaunaDB, and it was perfect. However, I couldn't figure out the documentation fast enough, so I switched to ol' reliable MongoDB Atlas and rewrote the database layer. Happy with how it turned out, I added Stripe for payments and finished up the product.
It's minimal, beautiful, and fast. Now I need to see how well it scales.
The second all Next.js thing I built started as a mobile app. It's a directory of all restaurants in Faisalabad, where my family lives in Pakistan. After the COVID flight lockdown ended, I went back home from Dubai to ride out the second wave. I was working on FlyFly my dad asked me if I'd be interested in building the directory.
Soon, we realized that people in Faisalabad prefer websites, as it's low commitment and faster than downloading apps. I built a website in Next.js with Firebase, which quickly grew as I added admin tools to add/edit/import restaurants from Google Places. Initially, I was using Firebase Storage, but then switched to Cloudinary for restaurant logos and added a cropping tool and asset browser to reuse previously uploaded logos to save on cost and bandwidth.
The design went through several iterations, and so did the database. As I added more features, Firestore started feeling limited. I tried FaunaDB with FlyFly and had limited success, but it felt right for FirstBite. So I dropped Firebase and refactored the database layer with FaunaDB. It's fast and brilliant and works well with the serverless nature of Vercel. However, FQL is a tricky beast. And the learning curve was quite steep.
You can take it for a spin. However, I'm keeping the source code private for now, as my dad requested.
Both FlyFly and FirstBite are 100% self-contained Next.js projects. When I first played around with Next.js, I wasn't a fan of the file-based routing since you can fetch once and reuse data with
create-react-app, but once I stopped letting that notion run things in my head, it became clear how brilliant Next.js is. The last version I played with was v4, and then straight to v9. And with v10, there's just no going back anymore. The mixing of server-side rendering and static site generation allows you to do great things.
For instance, on FlyFly, the plans are unlikely to change often, so the pricing page is generated statically with data fetched from the database. The landing and error pages are purely static. Everything else is rendered server-side.
For FirstBite, everything is rendered server-side for the moment, but as changes become less frequent, I'll switch to incremental static generation.
With Next.js API routes and authentication, I can power mobile apps with the same APIs that I use for my websites. I've already done that for FirstBite. I went with Expo for the FirstBite app to make development, publishing, and updates quicker.