Deploying a Next.js application at 3 different budgets

Written by Sam Haakman, Full-Stack Developer

Josephmark
6 min readJun 30, 2022
Two women at a computer
Josephmark Studio

At Josephmark, we work across industries ranging from fintech to sextech, and part of that work includes designing and building beautiful web apps for brand new ventures. While we’re very fond of the MVP (minimum viable product) approach to get a young product into the world and tested, we’re also comfortable working with established brands with vendor partnerships and complex availability and data sovereignty requirements.

Enter bass-slappin’ and drum-beatin’ Sam Haakman, a Full Stack Developer here at JM. While he’s been a full-time engineer for six years, he accepted his first paid dev gig all the way back in 2010. “Radical Honesty” has become the mantra weaving through his work and he certainly walks the talk, particularly when it comes to improving accessibility, speed, and flexibility on our projects. We were able to snag some of Sam’s precious time to give you a sneak peek into our engineering frameworks.

In this article, Sam is going to walk through how we approach deploying our preferred front-end web framework, Next.js at three levels of complexity and cost. Our solutions start at less than $1/month and ramp up to over $100/month.

1. Static Deploy @ 1c/mo

For our motion design studio, Breeder, we needed a quick and easy way of getting their portfolio online. The site has a small footprint and the content doesn’t change often so choosing a static deploy was an easy and super cost-effective solution.

Static Deploy — Breeder Studio

The stack

Breeder’s data starts off in Prismic, using their Community plan ($0/mo). We have three data types consisting of the homepage layout, case studies and career listings.

Next, we use Next.js’ getStaticProps function to retrieve data from Prismic and populate our UI. next/dynamic allows us to build flexible layouts using Prismic “slices” without ballooning bundle size.

We use Bitbucket Pipelines (50 mins/mo $0) to compile and deploy the codebase to AWS S3 ($0.01/mo) as well as request a cache purge from Cloudflare ($0/mo). The videos are simply hosted on Vimeo.

pipelines:
branches:
main:
- step:
name: Build & Export site to HTML
caches:
- node
- next
image: node:17-alpine
script:
- npm i --production
- npm run build
- npm run export
artifacts:
- out/**
- step:
name: Push Site to S3
deployment: production
image: atlassian/pipelines-awscli:latest
script:
- aws configure set aws_access_key_id "${AWS_ACCESS_KEY}"
- aws configure set aws_secret_access_key "${AWS_SECRET_ACCESS_KEY}"
- aws s3 sync --delete --exclude "*.html" --cache-control "public,max-age=31536000,immutable" out s3://${AWS_S3_BUCKET}
- aws s3 sync --delete --exclude "*" --include "*.html" out s3://${AWS_S3_BUCKET}
- step:
name: Purge Cloudflare
image: curlimages/curl
script:
- >
curl -X POST "<https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE}/purge_cache>"
-H "Authorization: Bearer ${CLOUDFLARE_KEY}"
--data '{"purge_everything":true}'
definitions:
caches:
next: .next

Finally, we set up a Lambda function (<1c/mo) to trigger the CD pipeline on a Prismic webhook whenever new content is published

const https = require("https")exports.handler = async (event) => {
const secret = JSON.parse(event?.body)?.secret
if (!secret) {
return {
statusCode: 401,
body: JSON.stringify({ message: "No auth found", request: event })
}
}
const data = await new Promise((resolve) => {
const req = https.request(
{
hostname: "api.bitbucket.org",
port: 443,
path: `/2.0/repositories/${process.env.BITBUCKET_REPOSITORY}/pipelines/`,
method: "POST",
headers: {
Authorization: `Basic ${secret}`,
"Content-Type": "application/json"
},
},
(resp) => {
let d = ''
resp.on("data", chunk => {
d += chunk
})
resp.on("end", () => {
resolve(d)
})
}
)
req.write(JSON.stringify({
target: {
ref_type: "branch",
type: "pipeline_ref_target",
ref_name: "main",
},
})
)
req.end()
})

const response = {
statusCode: data?.code || 200,
body: JSON.stringify({"message": "Yeah good", data, input: event}),
};
return response;
};

Pricing

  • Prismic $0
  • AWS S3 $0.01
  • AWS Lambda $0
  • Bitbucket Pipelines $0
  • Cloudflare $0

2. Managed hosting @ $20/month

We recently built the digital seller assistant web app for SWOP — a lovely local circular fashion retailer focused on high-quality pre-loved pieces. Being an established bricks-and-mortar business with early-stage digital capability, we didn’t want to commit them to a complex and high-maintenance custom-hosted solution. Next.js’ image manipulation and serverless functions aren’t available with a static export, so we took a middle road with managed hosting.

Managed Hosting — SWOP

The stack

SWOP utilizes the new FL0 alpha API tool ($0 up to 1m requests — leave a comment if you want to hear our review on this new tech!). Clothing brands, categories and prices all come from FL0. We’re using SendGrid to notify stores and sellers when they book a courier or in-store review, also triggered through FL0.

As before, we pre-load some data with getStaticProps. The layout here is fixed, although we still use next/dynamic to defer loading the heavier components inside the overlay.

For this project we’re hosting on Vercel ($20/mo/user) although we’re also partial to Netlify which has a similar feature set and pricing.

We decided to deploy via Pipelines in order to avoid adding our entire Bitbucket organization to Vercel billing.

pipelines:
branches:
main:
- step:
image: node:17-alpine
name: Prod Deploy
deployment: production
caches:
- node
script:
- npx vercel --prod -b BITBUCKET_COMMIT=$BITBUCKET_COMMIT -t $VERCEL_TOKEN

Pricing

  • FL0 $0
  • Vercel $20
  • Bitbucket Pipelines $0
  • SendGrid $0

3. Containerized Hosting @ $150+/month

Finally, we have our Big Bertha — the full-fat containerized deploy. We pull out this strap when we need maximum control over our stack and features like data-centre or availability zone redundancy, green-blue deploys and localized data sovereignty and security. As an added bonus, we can also run whatever backend we like without significantly increasing costs. Builds like josephmark.studio and thepeoplesgrid.com are where we flex this approach. $150/month is on the low side of how much a deploy like this costs, and ultimately the sky is the limit depending on project requirements. Features like data replication, machine learning compute and high-capacity databases will quickly balloon these numbers into the 4–6 figure mark.

Containerized Hosting — Josephmark

The stack

We’re not precious about CMS selection, but for the sake of argument, josephmark.studio uses Strapi for the backend. We’re making judicious use of the dynamic zone feature to enable our team to create composable layouts that keep to a pre-built style guide. Admins get access to build beautiful pages without the designers losing their nut over someone changing the font to Papyrus.

getStaticProps continues to be the star of the show for data fetching, but we also make use of Next’s preview feature alongside some custom Strapi code to allow content writers to preview draft case studies as they’re being written.

We run the front-end and back-end containers in an AWS ECS cluster and make use of Fargate serverless compute to back this app. Having front-end and back-end colocated helps to make more efficient usage of the available resources and they’re always scaleable if things start feeling sluggish. Database communication all happens within a private subnet, so it’s locked down tight against attacks.

To keep our compute instances super lean we also hand off the image optimization pipeline to a serverless Lambda function. This allows image optimizations to persist across deploys easily and the optimized images get cached by Cloudfront for super-speedy global availability.

We still lean on Cloudflare for their no-fuss security and performance features and run our CI/CD on Bitbucket Pipelines.

No configs here — that would be giving away the secret recipe. 😉

Pricing

  • AWS ECS $16
  • AWS Fargate Compute $58
  • AWS EC2 Load balancer $48
  • AWS RDS $25
  • AWS Lambda $0
  • AWS S3 $0.63
  • AWS Cloudfront $0
  • Cloudflare $0
  • Bitbucket Pipelines $0

This is just a tiny sneak peek into some of the frameworks we use here on the JM engineering team. Want to work on cutting-edge technology with other people who love learning and improving? We’re hiring talented engineers and want to hear from you.

By Sam Haakman, Full-Stack Developer

--

--

Josephmark

Design is our language. Venture is our mindset. We are Josephmark.