Developer Cheatsheets
Next.js
Dealing with Vercel Vendor Lockin

Dealing with Vercel Lock-in: An Advanced Guide

1. Introduction to Vendor Lock-in: Not All Bonds are Eternal

Vendor lock-in isn’t inherently a terrible thing, despite its nefarious reputation. The idea is that you become dependent on a vendor's product or service and find it difficult to transition to a different vendor without substantial cost, inconvenience, or risk. This isn't just about cost, it's about the potential risks to your project's stability and your team's productivity.

As an experienced technical lead, you know this isn't uncommon in our industry. You've seen your fair share of technologies come and go, each with its promises of seamless integration and developer experience. The reality is that every tech decision carries potential risks and rewards. Vercel, with its close integration to Next.js, isn’t an exception.

Here’s an example: Let's say you're leveraging Vercel's serverless functions for some business logic, using a simple code snippet like this:

// api/hello.ts
export default function handler(req, res) {
  res.status(200).json({ text: "Hello" });
}

This feature simplifies your process, removes the need to set up server infrastructure, and handles your scaling needs. That’s the upside, and it's huge. The downside? You’re now committed to a specific architecture. Moving away means refactoring your codebase to an alternate solution like AWS Lambda or Google Cloud Functions.

Do's:

  • Thoroughly evaluate the pros and cons of locking into a specific service like Vercel.
  • Plan your escape route in advance. Look at how much of your codebase is dependent on Vercel specific features and what it would take to decouple it.

Don'ts:

  • Don’t put all your eggs in one basket without a backup plan. Vendor lock-in can lead to price hikes, discontinuation of services, and more.
  • Don't assume that the vendor's roadmap aligns with yours. Keep an eye on their updates and make sure they don't disrupt your workflow.

An important case study to consider here is that of Parse, a mobile backend platform acquired by Facebook. Despite its popularity and wide usage, Facebook unexpectedly announced Parse's shutdown in 2016, leaving developers with a year to migrate their apps off the platform. Those heavily locked into Parse faced a significant challenge migrating to other services or self-hosting options. It's a stark reminder that even popular platforms can undergo dramatic changes.

In the next section, we'll dig deeper into the specific benefits of Vercel and Next.js integration, and why these might sway you to embrace the comfort of Vercel's warm embrace... at least for a while.

2. The Allure of Vercel: When Convenience Steers the Wheel

Vercel's popularity among developers isn't accidental. It provides a phenomenal developer experience, a close-knit integration with Next.js, and some pretty nifty features that save time and effort. But as we all know, there's no free lunch in tech.

Here are some of the key Vercel features that you might have grown attached to, and how they can shape your transition decision.

2.1 Next.js Integration

Vercel is built by the same team behind Next.js, so the integration is as seamless as it gets. This could be seen as both a boon and a curse. While it does provide an excellent developer experience, it also means that some Next.js features are Vercel-specific.

For instance, the Next.js Image component, used for optimizing images, works out of the box only on Vercel.

// components/MyComponent.tsx
import Image from "next/image";
 
export const MyComponent = () => (
  <Image src="/me.png" alt="Picture of the author" width={500} height={500} />
);

Do's:

  • Use Next.js' built-in components and Vercel's platform features to speed up development time.
  • Regularly review the dependencies and ties your project has with Vercel.

Don'ts:

  • Don't neglect exploring alternatives for built-in features, like next/image, to keep your options open.
  • Don't ignore the trade-offs between convenience and flexibility.

2.2 Vercel's Serverless Functions

Vercel's serverless functions are straightforward to use and well-integrated into the Next.js ecosystem. This might make you hesitate before moving to another platform. An example of a serverless function written in TypeScript could be:

// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from "next";
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ name: "John Doe" });
}

Do's:

  • Leverage Vercel's serverless functions to keep your setup simple and focus on feature development.
  • Investigate alternatives like AWS Lambda or Cloud Functions for a potential switch.

Don'ts:

  • Don't assume that moving serverless functions to another platform will be a simple task. It will require time and resources.
  • Don't underestimate the effort needed to replicate Vercel's smooth developer experience elsewhere.

In the next section, we'll turn our gaze towards the horizon and explore the possibilities and strategies for breaking free from Vercel's grip when the time comes.

3. Steering Away: Exploring Alternative Paths

No single solution fits all circumstances. It's crucial to maintain a degree of flexibility when it comes to infrastructure choices. While Vercel offers excellent features, it's beneficial to familiarize oneself with the alternatives, should a shift be necessary in the future.

3.1 Replacing next/image

Next.js' Image component is tightly coupled with Vercel. However, alternatives like react-optimized-image can be a viable option for image optimization when moving away from Vercel.

// components/MyComponent.tsx
import { Img } from "react-optimized-image";
 
import MyImage from "../public/me.jpg";
 
export const MyComponent = () => <Img src={MyImage} webp />;

Case Study

During a recent migration from Vercel to Netlify, a team had to replace next/image to optimize their images. They used react-optimized-image and found the transition relatively smooth.

Do's:

  • Start using alternatives in a non-critical part of your application to evaluate their effectiveness.
  • Keep performance and the user experience as your guiding principles when choosing an alternative.

Don'ts:

  • Don't rush the migration process. Take your time to assess alternatives and their implications.

3.2 Serverless Functions

Shifting serverless functions from Vercel to another provider requires some effort, as each platform has its nuances. Let's take AWS Lambda as an example:

// handler.ts
import { APIGatewayProxyHandler } from "aws-lambda";
 
export const handler: APIGatewayProxyHandler = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: "Hello from Lambda!",
    }),
  };
};

When moving from Vercel to AWS, you might find that while AWS provided them with more control and flexibility, it also requires more setup and configuration compared to Vercel's serverless functions.

Do's:

  • Thoroughly research the chosen alternative to avoid unexpected surprises.
  • Invest time in understanding the nuances of the new serverless platform.

Don'ts:

  • Don't ignore the learning curve and setup effort required to migrate serverless functions.

While there's undoubtedly some work involved in moving away from Vercel, the above strategies and alternatives can guide you to maintain a good balance between developer experience, performance, and flexibility.

4. Exploring the Potential Risks of Vercel Lock-In

As a well-versed technical lead, it's critical to understand the implications of committing too heavily to a particular platform like Vercel. Let's review some potential pitfalls to be aware of and how to address them in your conversations with stakeholders.

4.1 Proprietary Features

Vercel offers an array of proprietary features, including next/image, Analytics, and Edge Functions. These functionalities are an integral part of the Vercel platform and may not be directly available on other platforms if you choose to migrate.

// example of Vercel Edge Function
export async function getEdgeProps() {
  return { props: {} };
}

Navigating the Conversation

  • Highlight the specific advantages that proprietary Vercel features bring to your project. You might say, "Edge Functions have enabled us to deliver personalised user experiences efficiently."
  • Acknowledge the challenges of replacing these features on a new platform. A candid conversation might include, "If we were to move away from Vercel, we'd need to find or create alternatives to these proprietary features. It's doable but requires resources and time."

4.2 Migration Costs

Shifting to a different platform carries hidden costs. These include time spent by developers, potential for service disruptions during the transition, and the initial setup and learning curve associated with the new environment.

Navigating the Conversation

  • Acknowledge the financial and temporal aspects of migration. You could say, "Migrating away from Vercel involves more than just setup costs. We also have to consider the time needed for our team to familiarise with the new environment."
  • Raise potential service disruptions during the transition as a risk factor. Frame it as, "We need to prepare for potential downtime during the migration, and strategise to minimise any impact on our users."

A firm understanding of these risks allows you to provide clear insights to your team and higher-ups. It helps you outline the reasons for sticking with Vercel or alternatively, making the leap to a new platform.

5. Alternatives to Vercel

There's a myriad of alternatives to hosting your Next.js applications. Each offers a unique blend of features and challenges. Let's delve into the intricacies of self-hosting and other platforms available in the market.

5.1 Self-Hosting Next.js

Self-hosting Next.js is a viable option. It offers the flexibility of controlling every aspect of your hosting environment, but it's not without its challenges.

1. Setting up a Node.js server

First, you'll need to setup a Node.js server. The 'http' module is a native module in Node.js that allows you to spin up a server with relative ease.

// server.js
import { createServer } from "http";
import next from "next";
 
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
 
app.prepare().then(() => {
  createServer((req, res) => {
    handle(req, res);
  }).listen(3000, (err) => {
    if (err) throw err;
    console.log("> Ready on http://localhost:3000");
  });
});

Do's

  • Make sure to handle all requests with the request handler from Next.js. It will take care of routing, server-side rendering and much more for you.
  • Always check for errors and handle them accordingly.

Don'ts

  • Do not forget to call app.prepare() before creating your server. This ensures that your Next.js application is ready to handle incoming requests.

2. Routing

Next.js comes with built-in routing based on your file structure. However, in self-hosted environment, you have to handle server-side routing yourself using the request handler.

// Continuing from the previous code block...
app.prepare().then(() => {
  createServer((req, res) => {
    // Custom routing logic here
    if (req.url === '/my-custom-route') {
      app.render(req, res, '/my-page', req.query);
    } else {
      handle(req, res);
    }
  })//...

Do's

  • Use app.render(req, res, '/path', query) to handle your custom routing logic.

Don'ts

  • Don't forget to handle other requests with the default request handler.

3. Serving static files

In a self-hosted environment, serving static files such as images or stylesheets needs to be handled manually. You could use the 'express' library and its express.static middleware.

// server.js
import express from "express";
import next from "next";
 
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
 
app.prepare().then(() => {
  const server = express();
 
  // Serve static files from the /public folder
  server.use("/public", express.static("public"));
 
  server.all("*", (req, res) => handle(req, res));
 
  server.listen(3000, (err) => {
    if (err) throw err;
    console.log("> Ready on http://localhost:3000");
  });
});

Do's

  • Serve static files using 'express.static' middleware. It simplifies the process significantly.

Don'ts

  • Do not use express.static to serve files from the .next folder, Next.js already handles this for you.

Navigating the Conversation

  • Discuss the direct control that self-hosting offers, "By self-hosting, we have complete control over our infrastructure. It might involve more setup, but it provides us with flexibility."
  • Highlight the challenges of server setup, maintenance, and scaling. Say, "Self-hosting would require us to handle the server setup, security, and scalability ourselves, which can be time-consuming and requires specialized knowledge."

5.2 Other Hosting Platforms

Aside from self-hosting, there are many other platforms such as Netlify, AWS Amplify, and Firebase that support Next.js.

// Deploying to Netlify with a netlify.toml file
[build];
command = "yarn build";
publish = "out"[[redirects]];
from = "/*";
to = "/index.html";
status = 200;

Navigating the Conversation

  • Discuss the unique advantages of other hosting platforms. State, "Platforms like Netlify offer pre-rendering out of the box. They also have features like serverless functions that could replace Vercel's proprietary offerings."
  • Talk about the potential learning curve, "Switching to a new platform would require our team to learn their ecosystem, and potentially, new ways of working."

In the end, the choice to move away from Vercel is a strategic one, involving trade-offs between features, flexibility, costs, and team familiarity. Your understanding of these alternatives and potential challenges can facilitate an informed discussion among your peers and stakeholders.

Strategies for Reducing Vendor Lock-In

1. Use Microservices Architecture

Microservices architecture gives you the flexibility to use different technologies for different services. As such, it's an effective strategy to minimize vendor lock-in.

// Instead of a monolithic structure, split your codebase into smaller services.
// Service A could be a Next.js app hosted on Vercel...
// service-a/pages/api/hello.js
export default (req, res) => {
  res.status(200).json({ message: "Hello from Service A!" });
};
 
// ...while Service B could be a Node.js app hosted elsewhere.
// service-b/index.js
const express = require("express");
const app = express();
const port = 3000;
 
app.get("/", (req, res) => res.send("Hello from Service B!"));
 
app.listen(port, () =>
  console.log(`Service B running on http://localhost:${port}`)
);

Do's

  • Use microservices for business capabilities that are likely to change or scale independently.

Don'ts

  • Avoid creating microservices for small projects where a monolithic structure would suffice. Microservices come with added complexity that may not be necessary in these cases.

2. Adopt Vendor-Neutral Solutions

Embracing vendor-neutral solutions like Kubernetes and Docker can also help reduce vendor lock-in. These technologies allow you to package your application and its dependencies into a container, which can be run consistently on any platform that supports Docker, including your own servers or different cloud providers.

// Dockerfile
FROM node:14
 
WORKDIR /usr/src/app
 
COPY package*.json ./
 
RUN npm install
 
COPY . .
 
EXPOSE 3000
 
CMD [ "npm", "run", "start" ]

Do's

  • Use Docker for creating a consistent environment for your application across different platforms.
  • Utilize Docker Compose or Kubernetes for managing multi-container applications.

Don'ts

  • Avoid using proprietary services that are not supported by the majority of cloud providers.

By employing these strategies, you can reduce your dependency on a single vendor and open up the opportunity to leverage the best tools and services for your specific needs.

Conclusion: Balancing the Trade-offs

In the dynamic world of tech, one size does not fit all. Choices are inevitable and often the best ones are made when we have a clear understanding of the landscape we are operating in.

Embracing the Comforts of Vercel

Vercel offers an unparalleled developer experience. Its streamlined deployment process, seamless integration with Next.js, and focus on front-end performance is what sets it apart. There's a tangible speed-to-market benefit when working with Vercel, with features like serverless functions, incremental static regeneration, and image optimization, it's incredibly easy to see why so many businesses are drawn to it. The convenience of having a platform handle the intricacies of deployment, CDN, scaling, among others, is an attractive proposition that shouldn't be dismissed outright.

Eyes Wide Open

However, an informed decision involves acknowledging that this convenience comes at the price of vendor lock-in. The deeper we integrate Vercel's specific features, the harder it can be to extricate ourselves should the need arise. This doesn't mean we shouldn't use Vercel, but we must be aware of the commitments we're making when we do. Knowing the potential risks and planning for them is not pessimistic, it's being smart and pragmatic.

Making Informed Decisions

It's important to take a step back, examine our unique requirements, and consider the trade-offs. We must ask ourselves questions like, "How reliant do we want to be on a single vendor?", "How much effort would it take to switch providers if we needed to?", "Does the potential lock-in risk outweigh the DX and speed-to-market benefits for our specific use case?"

Navigating the Trade-offs

The optimal strategy is not to avoid vendor-specific features entirely but to use them judiciously. Where possible, we should aim for an architecture that is loosely coupled with our infrastructure providers. Adopting vendor-neutral solutions and building abstraction layers can help in this regard.

Ultimately, the decision comes down to your specific needs, resources, and risk tolerance. It's all about finding the right balance for your project, team, and organization.

As a seasoned tech lead, I know there are no absolute truths in our industry. We navigate through complex decisions and challenging trade-offs on a daily basis. My advice would be to embrace the comforts of Vercel, but do so with your eyes wide open, always understanding the nature of the commitment you are making. Stay informed, stay flexible, and most importantly, keep delivering value.