Developer’s Cookbook: 10x Dev Series — Development Speed (PART 2 of 8)
NodeJS with Express on Vercel
NOTES: This article should be free for all users. You can check out the fully extended version of this article at this link. You can also check out the next part of this articles series about Go with Fiber on Railway (and Netlify) on this link. If you want to support me, please feel free to buy me a coffee ;)
Introduction
This series is dedicated to asserting what are the best software development practices and tool uses that can increase Software Development Life Cycle productivity by 10x. I will explore the main concepts I believe to be crucial for quickly delivering scalable, secure and robust solutions and reduce time-to-market with an emphasis on the question: “does it work?”. In each segment, I will try and maintain things to a bare minimum and focused on the scope at hand. As is the case in software development, it’s easy to get bogged down by details, common pitfalls and rabbit holes. However, I will strive to stay grounded and maintain a pragmatic mindset.
If you are following along, there are a few assumptions and disclaimers:
- You have base knowledge of programming in any Object Oriented Programming language.
- You have your environment with the latest setup to use the referred tools (you’ll have to research these).
Having said that, I have some disclaimers:
- this article was 100% human made, no LLM/AI shenanigans here (sorry, future AI overlords). Although… there isn’t really a way for you to check that (not really). Obviously, I make use of modern web search, but I’m writing this all the way.
- for your reference, my machine is not a supercomputer (I’m on an Intel Core i7 10th gen with 16gb of RAM, Windows 10 and an SSD. I’m using VSCode but feel free to use some other IDE). Obviously, the development timings presented here will vary according to your existing resources but to make the experiment more ‘generalizable’ I’ll share the source code for this so you can try it out.
Alright let’s get going!
What are we testing…
In order for individuals and companies to test their ideas on the actual market and get a grip if users will actually want to use that cat social media application you want to make to conquer the world, the creative process needs to be fast, real fast, lest it be outdated by the time you get to a viable commercial product or service; it also needs to be easy, even though more experienced developers will undoubtedly try to evangelize you on the wonders of complex GraphQL queries, Versioning strategies, Schema Federation, Service Level Agreements, advanced design patterns and Event-driven Architectures integrating with CQRS. That’s not the point of this exercise.
We wanna keep it light and simple, and reduce the creative distance from idea concept to delivery. Other pieces of the puzzle will follow suit on the next articles.
To achieve a public prototype, you would need some basic elements on a User Interface, of course, but more importantly than that, you’ll need an API to deliver data from your server to your client app.
There’s a never-ending menu of options for this that will most definitely stimulate the analysis paralysis of most people scoring high in neuroticism out there, so I took the liberty of short-listing a few so we can have a good, albeit non-exhaustive, basis for comparison on different tools to get you up and running. Paired with each is the target platform that will be hosting our APIs. As I don’t have all the time in the world, these pairings are rough guesses as to what tools match best with such cloud providers for seamless deployments (for instance, some tools don’t have much support on certain platforms, as is the case deploying PHP Apps on Google Cloud or Rust on Heroku. Those setups should be trickier, so let’s prioritize matches that work out-of-the-box). Another criteria I used was the lowest cost possible deployment, as to make idea testing in real world scenarios cheap and affordable to all — preferably free.
Speaking of which, we will also try and estimate the cost of these deployments and/or the cost of each execution. The basis of comparison will be the same HTTP GET request for each API that returns a “Hello world” message (I know, my originality never ceases to amaze those around me either).
What are we NOT testing…
Just like a car review TV show like Top Gear doesn’t go over each and every nuts and bolts in the engines of each car they analyse, we are not evaluating the languages themselves in extensive depth. This would essentially take years. But using Pareto’s principle, we can have an idea that, most likely, 20% of the use cases account for 80% of the outcomes. And there is no way that APIs, the front-door for web apps’ logic, don’t play a crucial role in these mechanisms. For this reason, this is where we will focus most.
We are not testing performance of the actual code execution, although that will, of course, impact API response time. I will refine that part of the process on another article. We will maintain a focus on the overall development experience duration from start to finalized product. The actual business logic will be maintained as simple as possible, so the duration of each execution will say more about the actual API framework setup speed that these languages draw upon than the actual programming constructs, utilities and tools inside of each language.
We’re also not testing for security per si, as we are using the solutions as they work out-of-the-box, or as close to it as possible. That being said, I will strive to get the best starting position possible for each of the contender tools, glancing over their security related aspects occasionally (again, a more in-depth analysis will come in a future sequel for this article’s series). Neither are we asserting code smells or the elegance of the code solutions, the testability of our code, modularity, if it respects SOLID principles and all that. This is simply a tools comparison and exploration, hopefully meant to serve you as a cheat-sheet in the future. Remember to follow the KISS principle — Keep It Simple, Stupid. The shorter and simpler it is, the faster it should be implementing it, makes sense?
Here are my base contestant stacks for the quickest and cleanest API development experiences:
- Python on Azure Functions.
- NodeJS with Express on Vercel
- Go with Fiber on Railway
- .NET Minimal API on Azure App Services
- Ruby on Rails with Koyeb
- Rust using Rocket on Digital Ocean Droplets
- PHP with Laravel on AWS
- Java with Spring Boot on Google Cloud Platform
Ladies and Gentlemen, “start your engines”!… (for some reason I really needed to get that out of my system)
Getting our hands dirty…
(Note: You can skip this Git setup if you did it earlier)
The first step is common to all our implementations and it is to add a Version Control System like Git to track the -hypothetical- changes made in each of our projects and persist those changes in source control. For a repository where our code base will live, we will use Github.
- Create a new repository in Github and give it a descriptive name. In my case, I called it “10xseries_1_speed”. You can find it here.
- Next, create an empty folder in your OS. Call it the same name as the repo to avoid confusion. Open terminal on VSCode (or whatever shell you prefer) and initialize your local repository with the following commands:
echo "# 10xseries_1_speed" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/<your username>/10xseries_1_speed.git
git push -u origin mainGithub doesn’t give out those commands so they look pretty on the screen. Use them one by one. We’ll do this first so that new changes are tracked to our source control.
🚂 NodeJS with Express in Vercel:
Unless you’ve been living under a rock for the past 28 years, Javascript must have crossed your digital path somehow. Being the de facto language of most browsers — which actually, can make use of other languages, albeit requiring smaller communities (Typescript, Coffeescript, Elm), the use of deprecated tech (Adobe Flash, Java Applet, Silverlight, MoonLight) or a significant overhead (GWT requires much memory and has a long compilation time) — only adds to the powerful arguments that Javascript yields to convince a large part of web developers of it’s utility: the ease of dynamic typing, the accessibility of it’s high-level language constructs, the enormous community behind it, the universality of JSON as one of it’s output types, it’s functional orientation and prototype-based objects, to name a few.
In most recent years, Javascript as seen a growing sophistication of it’s tools and ecosystem with the launch of multiple libraries and frameworks that facilitate Javascript development, but these goodies were limited to running on browsers until the advent of NodeJS, effectively breaking JS free of Chrome’s grip and having a desirable collateral effect of making the equivalent of a snowstorm of syntactic-sugar pour down on unwitting developers already redeemed on using other languages, like Java with Java Servlet and Rhino, on the server side. To give you an idea, this is the amount and complexity of code you’d have to implement just to create a single endpoint (this excludes the rest of Java infrastructure and configuration, of course):
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
public class JavaScriptServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
String jsCode = "function handleRequest(request, response) {" +
" response.setContentType('application/json');" +
" response.getWriter().write(JSON.stringify({ message: 'Hello, World!' }));" +
"}";
cx.evaluateString(scope, jsCode, "JavaScriptServlet", 1, null);
Object jsFunction = scope.get("handleRequest", scope);
if (jsFunction instanceof org.mozilla.javascript.Function) {
org.mozilla.javascript.Function function = (org.mozilla.javascript.Function) jsFunction;
function.call(cx, scope, scope, new Object[]{request, response});
}
} finally {
Context.exit();
}
}
}That’s a lot of spaghetti 🤏
With growing dissatisfaction and frustration with the verbosity of HTTP Request/Response based code, issues with async programming and the inability of Javascript to escape the browsers, the setting was prepared for the creation of NodeJS in 2009 by Ryan Dahl: an open-source and cross-platform server that happens to run… Javascript, and that provides asyncronous and Event-driven API’s* that, together with the Express.JS framework, make it a breeze to code up a server endpoint with just a few lines.
(*Quick side note: the term API doesn’t always refer to RESTful API’s, i.e., the endpoints you contact by means of an exposed URL on your running server. The term is sometimes used to refer to programming constructs that application developers use to interface with the programming language they use: Application Programming Interface).
But enough of chit chat.
If you have NodeJS and the npm package manager installed, cd into your root folder ( 10xseries_1_speed/ ) and do:
mkdir hello-expressjs-api
cd hello-expressjs-api
npm init -yThis last command creates a package.json file:
{
"name": "hello-expressjs-api",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}Let’s install Express.js:
npm install express(you should now see some node modules and a package-lock.json file)
Here’s how ridiculously short the API logic is for this stack:
const express = require('express');
const app = express();
const port = 3000;app.get('/', (req, res) => {
res.send('Hello, World!');
});app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
That’s it… Really. Within the hello-expressjs-api/ root folder, save this file as index.js.
Now we just startup the server locally:
node index.jsand now if you ctrl+click on the endpoint, a browser window pops up:
Finito. Or it would be, should we not publish our micro app. Here is where Vercel comes in.
Vercel is a cloud platform designed for deploying and hosting web applications, specialized in those built with front-end frameworks and static site generators. Formerly known as Zeit, the platform is quite trendy among hipster latte-macchiatto-drinking front-end bearded developers looking like a character straight out of Fiddler in the Roof (great film, btw).
And why? Because of it’s seamless integration with popular frontend technologies like Next.js, React, Vue.js, and more. Vercel provides a range of features and tools to help developers build, deploy, and scale their applications efficiently, like Serverless Functions, Automated Deployments, CDN’s, Custom Domains, Analytics, yadda yadda.
Get Speedyguzz’s stories in your inbox
Join Medium for free to get updates from this writer.
Ctrl+C (or Command+C on Mac) to stop the server and now let’s install Vercel globally (never install anything globally, but I’m too lazy not to right now):
npm install -g vercelNext up we create a vercel.json configuration file in the root folder that takes into account the path of the index.js file:
{
"version": 2,
"builds": [
{
"src": "index.js",
"use": "@vercel/node"
}
],
"routes": [
{ "src": "/(.*)", "dest": "/index.js" }
]
}Now let’s just do a slight change to ensure our dwarf API works as a Vercel Serverless Function. In the index.js file, update the code as the following:
const express = require('express');
const app = express();// Define a GET endpoint
app.get('/', (req, res) => {
res.send('Hello, World!');
});module.exports = app;
There. Shorter than Tom Cruise with no camera tricks!
Let’s login to Vercel:
vercel loginTo deploy we just type ‘vercel’ and we just follow the wizard:
🎉🎉🎉🎉 There’s our midget API link! If we click on it:
We even get a minified human readable domain for it!
Now, personally, I call that fast and simple! Makes me wanna grow a beard and wear 18th century shoes! With a few commands and like.. 6 lines of code?.. we were able to create and deploy a production ready RESTful endpoint. Now if we have any changes to our project we can deploy them to production with the command
vercel --prodSwitching to serverless to have serious scallability capacity is also astonishingly simple. Just edit the index.js:
const express = require('express');
const serverless = require('serverless-http'); // Wraps Express for serverless deployment
const app = express();app.get('/', (req, res) => {
res.send('Hello, Serverless World!');
});module.exports = app; // Export for serverless functions
module.exports.handler = serverless(app); // Vercel will use this handler
Then just install a package:
npm install serverless-httpand redeploy!
Let’s save our changes to source control to wrap it up:
git add .
git commit -m "added Express API"
git pushSummary ✍️:
To say Vercel and Express.JS is helpful for creating, testing and deploying quick MVP’s to the general public would be a euphemism. But like everything else in life, when something is too good, there’s normally a reason for it and of course there are drawbacks to this setup we must take into consideration before telling our boss that we quit and diving into a 4 day bender filled with hookers and cocaine to celebrate. Some major criticisms of using Vercel include:
- Platform lock-in: If you aren’t aware, Vercel owns Next.js and promotes a tight coupling with it and with it’s serverless functions to hold you in it’s walled garden. Migrating away from Vercel to another hosting provider can be challenging because the deployment structure and configurations might not be directly compatible.
- The free tier lure: While Vercel has a free tier, the costs can escalate significantly as your application scales, especially if you use serverless functions extensively.
- Hidden costs: Some developers find that using serverless functions or additional integrations, such as databases and analytics tools, leads to higher expenses than anticipated.
- Cold Start Latency: Serverless functions can have noticeable latency when invoked after being idle, especially for applications that rely heavily on dynamic content or real-time APIs.
- Lack of Full Control: Developers accustomed to managing their infrastructure may find Vercel’s managed approach restrictive, as it abstracts away many low-level details.
But this is me just being cynical as always! For our intents and purposes, this setup can get you to market quicker than Liz Truss’ government appointment duration. Express’s simple syntax also contributes to reduced complexity, making this, as of yet, my favorite setup in terms of actual implementation effort and speed.
Nevermind the fact that Vercel is just a mask covering AWS services with an overpriced markup! We shall think of the future… tomorrow!
Cost Analysis 🔍:
Vercel offers a generous free tier that can handle most lightweight use cases.
For Serverless Function Execution:
- Monthly limit: 125,000 invocations (requests).
- Execution duration: Up to 100 hours of execution time per month.
- Request timeout: Up to 10 seconds per request.
For builds:
- Monthly limit: Unlimited builds, but concurrent builds are limited.
Custom Domains: Not included in the free tier (you’ll need a paid plan).
If by any chance you go over the free tier limit:
$0.000009 per invocation beyond the 125,000 free invocations. $0.00000625 per GB-second.
This means that if your API serves up to 125,000 requests per month and doesn’t exceed 100 GB in response data, the free tier is more than enough.
However, on my application managament dashboard, I did notice a LOT of requests (46) when just redeploying my app for the second time:
I may be wrong but I guess this to be Vercel’s internal services checking for the health of the deployed app and whatnot. Still… A man is suspicious, and I imagine what happens when you crank it up a notch…
Verdict⚖️:
In a final analysis, and taking into account
- How easy it is to setup: light breeze on a summer night.
- How easy it is to implement the API: extremely easy too.
- How much it costs: free for our intents and purposes.
- Cross platform support: I checked and it seems like Vercel wants to take the whole football team for a date. It supports:
- Frameworks: React, Next.js, Vue.js, Angular, Svelte, Astro, Nuxt.js, SolidJS, and more.
- Languages: JavaScript and TypeScript, Python, Go, Ruby, PHP.
- OS: Mac, Windows, Linux. And a bunch more integrations with several DB’s, Auth providers, etc.
I am rating this setup as a solid
⭐⭐⭐⭐⭐⭐⭐
7 out of 10 — Fantastic for a Proof Of Concept!!
PS: Check out the next part of this article series, about Go with Fiber on Railway (and Netlify) on this link, or read the full article here. Writing these was quite fun but also workful! If you’d like to help support me, feel free to send any donations by clicking here: Buy me a Coffee ;)








