YouTube Transcript:
How To Avoid Big Serverless Bills
Skip watching entire videos - get the full transcript, search for keywords, and copy with one click.
Share:
Video Transcript
as you all probably know by now versel
and I broke up I still use them for a
lot of the things I'm shipping but they
are no longer a channel sponsor that
means I can talk about things they might
not have wanted me to talk about in the
past and today we're talking about a big
one how to not have a crazy versell bill
I see a lot of fear around how expensive
verell is and these terrible bills that
float around online I've had the
pleasure of auditing almost all of them
as in I've Doven into code bases that
caus these huge bills and I've learned a
ton about how to use Rell right and more
importantly the ways you can use it
wrong so I did something I have not done
before I built an app to Showcase just
how bad things can be I did all of the
stuff that I have seen that causes these
big versell bills and we're going to go
through and fix them so that you can
find them in your own code base and
prevent one of these crazy bills as I
mentioned before verell has nothing to
do with this video they did not sponsor
it but we do have a sponsor so let's
hear from them really quick [Applause]
[Applause] [Music]
[Music] [Applause]
[Applause] [Music]
[Music] [Applause]
[Applause]
this seems like the most innocent thing
in the world you put a video in the
public directory you put it in a video
tag and then you go to your website now
the video is playing this is great right
totally safe fine except that for CS
infra is expensive for bandwidth I know
people look at it and then they compare
to things like hetner and they're like
wow versell charges so much for
bandwidth the reason is everything you
put in this public directory gets thrown
on a CDN and good cdns are expensive the
reason you'd want things on a CDN is
because stuff like a favicon which is
really really small is really really
beneficial to have close to your users
even Cloud flare has acknowledged this
when they built R2 because R2 despite
being cheaper to host files is much much
slower than the CDN here because of that
putting stuff in this folder is
expensive and if it's something that you
can't reasonably respond with in a
single like chunk of a request it
shouldn't go in here my general rule is
if it's more than like 4 kilobytes do
not put it in here if you want the
easiest thing to put it in we'll have a
small self plug throw it an upload thing
I'm going to go to my dashboard we're
going to create a static asset host create
create
app files
upload go to the public folder grab drop
upload now all I have to do copy file URL
URL
go back here and just swap the source
out that's it we just potentially saved
ourselves from a very very expensive
bill because we don't charge for egress
on upload thing so instead of
potentially spending thousands of
dollars go drag and drop it into upload
thing and spend zero instead you can
also throw it on S3 or R2 or other
products all over the internet but this
is the one we built for next devs and it
makes avoiding these things hilariously
easy on the topic of assets though there
is one other Edge case I see people
coming into and I made a dedicated
example for this this page grabs a
thousand random Pokemon
Sprites and there's a lot of them and
they take quite a bit to
load this is doing something right that
I think is really really important we're
using the next image component and this
is awesome because if we were using our
own images like we had put in public
instead of serving the 4 megabyte Theo
face this could compress it all the way
down to like three kilobytes depending
on the use case but the way that versel
bills on the image Optimizer is really
important to note by default on a free
plan on versel you get a th000 image
optimizations by default but then they
cost $5 per thousand you get 5,000 for
free on the pro tier but that $5 per
thousand optimizations that's not cheap
and we made a couple mistakes in this
implementation one is that we are just
referencing these files that are already
really small the ones we're grabbing
from this GitHub repo poke AP API these
are already small files they don't
really need to be optimized it's nice if
the other one for sell CDN but it's not
necessary the much bigger mistake we
made is how we indicate which images
we're cool with optimizing you'll see
here that we're allowing any path from
GitHub user content so if other people
are hosting random images on GitHub they
could use your optimization endpoint to
generate tens of thousands of additional
image optimizations and I want to be
clear about what what an image
optimization is if you were to rerender
these below at a different size so we
were to change this to 200 a lot of
platforms Will Bill you separately for
the different optimizations if we make a
version of this image that's 1,000
pixels wide and tall and a version
that's 200 you would pay for both but on
versell you're only paying based on the
unique URLs the important thing to make
sure you do right here is that you
configure the path name to be more
restrictive so the quick fix for this
one is pretty simple you grab more the
URL so we go here we say /on API Sprites
Master starstar now this app will only
optimize images that come from Pokey API
so as long as this repo isn't
compromised you're good this also goes
for upli thing by the way if you just
call utfs doio here which a lot of
people do you just set it up so any
image on upload thing is optimizable
through your app what you want to do is
use the SL a SL style URLs because these
URLs allow you to specify an ID that's
unique to your app so in the example I
gave earlier if we were to use upload
thing to be the original host the E ID
is just this part right
here and now we can only optimize the
images as long as if they are coming
from my app because this is the path for
files that are from my app and you
cannot serve files from other people's
apps if you put the app ID in it like
this so if you're using upload thing and
you're also using the next image
component to optimize the image as
upload thing please make sure you do it
this this way and if you want to change
the URLs over the API will start doing
these by default soon but if you're
doing this early enough where that
hasn't happened copy file URL grab this
part put that after here so if we wanted
to put this optimized image on the
homepage image let's import the image
component from next in the
source will be https utfs doio
a did it get that correct from my config
it did look at that good job cursor now
that we've done this I can grab an
optimized image from my host which is
upload thing you don't have to pay for
somebody potentially going directly to
that URL because we eat that with upload
thing and users are now getting a much
more optimized image sent down to them
instead of the giant 10 megabyte thing
that you might be hosting with upload
thing and you don't have to worry about
users abusing it because if they don't
have the file in your service they can't
generate an optimized image this covers
a comically large amount of the bills
and concerns I've seen so make sure
you're doing this optimize your images
especially if you're still putting them
on verel for some reason and ideally
take every single asset you have that is
larger than a few kilobytes and throw it
on a real file host because vell's goal
is to do things so they're really fast
when you put them in the public folder
because if you put something like an SVG
or a favicon it needs to go really quick
which makes it more expensive but you
can even use for sales blob product
which is similar to upload thing R2 S3
all of those it immediately wipe these
costs out ideally they would introduce
something in the build system that Flags
when you have large files here and the
potential risk I might even make a
eslint plugin that does this in the
future but for now just make sure you're
not embedding large Assets in a way that
they get hosted on versell thing one
complete okay that's just bandwidth but
serverless is so expensive you got to
make that cheap too let's get to it
let's say you made a Blog and you have a
data model that includes posts comments
and of course users both posts and
comments reference users and you can see
how one might write a query that gets
all of these things at once but let's
say you started with just posts and you
made an endpoint that Returns the posts
then you added comments so you added a
call to your DB to get the comments and
then you added users so you added a
bunch of calls to grab the right user
info for all the things you just did you
might end up with an API that looks a
little something like
this hopefully y'all can quickly see the
problem here I was surprised when one of
those companies with a really big Bill
could not the problem here is we do this
blockin call cx. db. posts. findfirst to
get the post then we have the comments
which we get using the post ID then we
have the author which we also get using
the post idid well the post user ID then
we get the users in comments by taking
all the comments selecting up the user
ID and selecting things where those match
match
this is really really bad it is
hilariously bad because let's say your
database is relatively fast each of
these only takes 50 milliseconds to
complete blocking for 50 milliseconds
blocking for another 50 blocking for
another 50 locking for another 50 this
is 200 milliseconds minimum of compute
that should probably be a single
instance the dumb Quick Fix is to take
things that can be happening at the same
time and do them at the same time so we
can grab comments and author at the same
time a quick way to do this make the
comments promise don't block for it make
the author promise don't block for it
now these are both going at the same
time and if we need the comments here
which we do con comments is a wait
comments promise now we have them now at
the very very least we took these two
queries and allow them to run at the
same time but we can do much better than
this this is a real quick hack fix if
you don't have dependencies like if all
of these queries don't share data you
could just run all of them at once in a
promise do all settled but ideally we
would use SQL so I could write this
myself instead we're going to tell
cursor to change this code so a single
Prisma query is made that gets all of
the data in a single pass using relations
look at
that hilariously simpler db. post. fine
first order by down but we're also
telling it to include the user because
that's the author as well as comments
but in those comments we also want to
include user so we get all of the data
back directly here here they're cleaning
up because the data model I actually had
for this was garbage but honestly when
we get this back we have post which has
the user in it which is the author I
should probably have named that properly
whatever too late now and we have com
which have users as well as the comment
data all in one query this means that
this request takes four times less time
to resolve and I you not one of
those massive versell bills I saw
requests were taking over 20 seconds and
the average request had over 15 blocking
Prisma calls most of which didn't need
data shared with each other so a single
promise.all cut their request times down
by like 90% then using relations cut it
down another like 5% and I got the
runtime down in an Uber and 30 minutes
from over 20 seconds the requests were
often timing out down to like two in
very very little time in an Uber without
even being able to run the code you need
to know how to use a database and one of
my spicy takes is that forel's
infrastructure scales so well that
writing absolute garbage code like that
can function if you were using a VPS and
the average request took 20 seconds to
resolve I don't care how good bps's are
you wrote something terrible and your
bill is still going to suck or users are
going to get a lot more timeouts or
requests bouncing because the server is
too busy doing all of this stuff verell
did just add a feature to make the issue
here slightly less bad which is their
serverless servers announcement check
out my dedicated video on this if you
want to understand more about it the
tldr is when something is waiting on
external work other users can make
requests on the same Lambda so each
request isn't costing you money because
if these DB calls took 20 seconds then
every user going to your app is costing
you 20 seconds of compute with the new
concurrency model at the very least when
you're waiting on data externally other
users can be doing other things so it
reduces the bill there a little bit and
by a little bit I mean half or more
sometimes so it is a big deal especially
if you have long requests like if you're
requesting to an external API for doing
generation for example very good use
case for doing something like this if
you're waiting 20 plus seconds for an AI
to generate something for your users
paying the 20 seconds of waiting for
every single user sucks and this helps a
ton there there are other things we can
do to help with that though one of those
things I didn't take the time to put it
in here is queuing instead of having
your server wait for that data to come
back you could throw it in a queue and
have the service that's generating your
stuff update the queue when it's done
there are lots of cool services for this
inest is one of the most popular had a
really good experience with them they
allow you to create durable functions
that will trigger the generation and
then die and then when the generation is
done trigger again to update your
database really cool in order to avoid
those compute moments entirely another
that I've been talking with more is
trigger. deev open source background
jobs with no timeouts this lets you do
one of those steps where you're waiting
a really long time for Dolly to generate
something without having to pay all of
the time to wait for your service
sitting there as you this thing is being
generated so if you do have requests
that have to take long amounts of time
you should probably throw those in a
queue of some form instead of just
letting your servers eat all of that
cost these Solutions all help a ton be
it a que or the concurrency stuff that
verell shipping at the very least you
should go click the concurrency button
because it's one click and might save
you 80% of your bill all of the things I
just showed assume that the compute has
to be done but you don't always have to
do the compute sometimes you can skip it
let's say theoretically this query took
a really long time it didn't take 100
milliseconds maybe it takes 10 seconds
but also the data that this resolves
doesn't change much we can call things a
little bit differently if we have const
cached post call equals unstable cach
stable version of this coming very soon
as long as versel gets their stuff
together before next conf here I need to
import DB now we have this function
cached post call I should name this
better because post call has a specific
meaning cached blog post fetcher now
with the special cach blog post fetcher
function the first time it's called it
actually does the work but from that
point forward all of the data is cached
and now you don't have to do the call
again so if this call took 10 seconds
now it's only going to take 10 seconds
the first time this is a huge win because
because
now future requests are significantly
cheaper and if you can find the points
in your app where things take a long
amount of time and don't change that
much huge win but they do change
sometimes and it's important to know how
to deal with that so let's say we have a
leave comment
procedure it's a procedure where a user
creates a comment so context DB comment
create and we create this new comment
let's not return just yet though we'll
await this const comment equals that but
now this old cache is going to be out of
date and it's not going to show the
comment because this page got fetched
earlier that's pretty easy to
fix all you have to do is down here
revalidate tag post and now since we
called revalidate tag with this tag
versel is smart enough to know okay this
cash is invalid now so the next time
somebody needs the data we're going to
have to call the function again but now
you only have to call this query which
which we are pretending is very slow
once per comment so when a user leaves a
comment you run this heavy query but
when a user goes to the page you don't
have to because the results are already
in the cache we've just changed the
model from every request requires this
to run to every comment being made
requires it to run but then nobody else
has to deal with it from that point
forward huge change a common one I see
is users who are calling their database
to check the user and get user data on
every single request that is a database
call that is blocking at the start of
every single request you do if instead
you cach that user data then most of
those requests will now be instantaneous
instead of being blocking on a DB call
huge change so this will not only make
your build cheaper it'll also make the
website feel significantly faster you
don't have to wait for a database to be
called in order to generate this
information I'm seeing some confusion
about unstable cach I want to call these
things out this cash isn't running on
the client at all the client has no idea
about any of this things like react
query things like St while R validate
all of that stuff for the most part is
client side things to worry about this
is the server the server is making a
call to your database to get this data
and you are telling the server when you
wrap it with unstable cache hey once
this has been done you don't have to
call the database anymore you can just
take the result this is kind of just a
wrapper to store this in a k TV store
invers cells data center or if you
implement it yourself wherever else you
could do this Yourself by writing the
function a little differently I'll show
you what the DIY version would look
like DIY cach blog post so first thing
we have to do is check our KV so I'm
assuming we have a KV const KV result
equals yeah await kv. getet poost I
don't actually have a KV in here so
ignore the fact it's going to type error
if KV result return KV result otherwise
we set the result and then we return it
this is effectively what vel's cash is
doing they have some niceties to make it
easier to interrupt with and validate
things on I've diy things like this so
often in my life versel gave us some
synx sugar for it but you can DIY this
if you want to yourself I could rewrite
the unstable cache function and just
throw it in KV if I wanted to but this
is using a store in the cloud to C cash
the result of what this function returns
so you don't have to call it again if
you already have the result as you see
here if we have the result we just
return it from the KV otherwise we run
the other code again think that help
clarify that one that all said if you
know anything about blog posts you might
be suspicious of this example in the
first place because you shouldn't have
to make an API call to load a blog post
you should be able to just open the page
and have the blog post and here's
another one of those common failures I
see you might have even noticed it
earlier if you're paying close enough
attention see this export cons Dynamic
equals force Dynamic call here
this forces the page that I'm on to be
generated every time a user goes to it
this page doesn't have any user specific
data we have this API call but this one
doesn't use any user specific data we
have this void get latest. prefetch call
which allows for data to be cached when
things load on the client side we don't
even need that though we can kill it
nothing on this page is user specific so
loading this page shouldn't require any
compute at all but because we set it to
be dynamic it will and this whole page
is going to require compute to run on
your server every time someone goes to
it if you have pages that are mostly
static like a terms of service page a
Blog docs all of those things it's
important to make sure the pages being
generated are static thankfully verell
makes this relatively easy to check if
you run a build they will just show you
all of these details in the output and
they don't just show it when you run the
build locally I can also go to my verell
deployments and go take a look so we'll
hop into quick pick which is a service I
just put out and in here we can take a
look the deployment summary and see what
got deployed in what ways we have the
static assets the functions and the ISR
functions and it tells you which does
what the more important thing that's a
little easier in my opinion to
understand is in the build output it
shows you here each route and what it
means so the circle means static the f
means Dynamic and you want to make sure
all of your heavy things like your pages
that are static are static because you
want the user receiving generated HTML
you don't want to have a server spin up
to generate the same HTML for every user
when they go to every page back to image
optimization for a sec CU I know I
showed you how to use them right and as
long as you have less than 5,000 images
honestly you should probably use their
stuff it is very good and very
convenient despite being pretty happy
with the experience of using the next
image component on versel once you break
5,000 images price gets rough that's why
the example loader configurations page
is pretty useful here frankly I'm not
happy with either the pricing or the DX
around any of these other options but
they are significantly cheaper if you
want to use them sometimes sometimes
they're more expensive but for the most
part all the options here are cheaper
they have their own goas I've been to
Hell in back with Cloud flares to the
point where I'm putting out my own thing
in the near future if you need to save
your money now take a look through this
list and find the thing that fits your
needs the best but in the future image.
engineering is going to be a thing I am
very excited about this project I've
been working out in the background for a
while if you look closely enough at the
URLs on pck thing you'll see that all of
the URLs on this page are being served
by image. engineering already we're dog
fooding it we're really excited about
what it can do and in the near future
you'll be able to use that too so for
now if you need to get something cheap
ASAP go through the list here if this
video has been out for long enough or
maybe just check the pin comment I'll
have something about image engineering
if it's ready but for now use for sell
until you break for, images if the bill
gets too bad consider moving to
something like anything in this list and
keep an eye out for when our really
really fast and cheap solution is ready
to go which will be effectively a drop
in and have some really cool benefits as
well so yeah one last thing there's a
tab in everyone's versell dashboard for
everyone's versell deployments that
seems very innocent analytics you will
notice that you not have it enabled
there's a reason for that these
analytics events are not product
analytics if you're not familiar with
the distinction product analytics are
how you track what a user does on your
site so if you want to see which events
a specific user had that's product
analytics to track the Journey of a user
if you want to know which Pages people
are going to you want to have a count
for how many people go to a specific
page that is web analytics web analytics
is like the old Google analytics type
stuff product analytics is things like
amplitude mix panel the tools that let
you track what users are specifically
doing my preference on how to set this
up is to use post hog and thankfully
they made a huge change to how they
handle Anonymous users they also made a
really useful change to their site the
mode which hides all of the crap it
makes it much nicer for videos so thank
you to them for
that but what we care about here is the
new pricing where it is
0.005 cents per event and that is the
most expensive ones and the first
million are free so you get a million
free events the next million are at this
price but if you're doing a million
events you're probably doing two million
events this is the more fair number so
we're going to take this number we're
going to compare it here so that is at
100,000 events times this
$343 versus 14 bucks pretty big deal
there interesting apparently the web
analytics plus product has a cap for how
many events you can do a month even in
the Pro window Enterprise can work
around it but 20 million events is a
pretty hard cap like we can even get
close to that with upload thing so yeah
not my favorite certainly not at the $14
per 100,000 event pricing and certainly
not for 50 bucks a month generally I
recommend not using the versel analytics
but if they do get cheaper in the future
I'll be sure to let you guys know so you
can consider it one last thing if you
are still concerned about the bill I
understand the thought about having some
massive multi thousand bill out of
nowhere is terrifying they have a
solution for that too spend management
you can set up a spend limit in your app
if you are concerned about the price
getting too
expensive you can go in to the spend
management tab in Billing and specify
that you only want to be able to spend
up to this much money and even manage
when you get notifications so if you are
concerned that usage will get to a point
where you have a really high Bill there
you go Bill handled it does mean your
service will go down so there's a catch
there but the reason this is happening
is either you implemented things really
wrong or your service went super viral
for what it is worth I have never
enabled this because the amount of
compute each requests cost for us is
hilariously low so even when we were
being dosed the worst Bill somebody
could generate was like 80 bucks after
spamming us for hours straight with
millions of computers because they found
one file on one of our apps that was
like 400 kilobytes so if you one things
well you almost certainly won't have
problems my napkin math suggested that
for us to have a $100,000 a month Bill
we'd have to have a billion users so
you're probably fine but if you are the
nervous type I understand go hit the
switch I hope this was helpful I know a
lot of y'all are scared about your for
sale bills but as long as you follow
these basic best practices you can keep
them really low our bill has been like
$10 a month for a while and not counting
seats it's not a big deal High recommend
taking advantage of these things and
continue using things like for sale all
of these tips apply other places too
it's not just for sale you can use these
same things to be more successful on
netlify cloud flare any other serverless
platform and these things will also
speed up your apps for using a VPS build
your apps in a way that you understand
and try your best to keep the complexity
down in the end the bill comes from the
things you shouldn't be doing until next
Click on any text or timestamp to jump to that moment in the video
Share:
Most transcripts ready in under 5 seconds
One-Click Copy125+ LanguagesSearch ContentJump to Timestamps
Paste YouTube URL
Enter any YouTube video link to get the full transcript
Transcript Extraction Form
Most transcripts ready in under 5 seconds
Get Our Chrome Extension
Get transcripts instantly without leaving YouTube. Install our Chrome extension for one-click access to any video's transcript directly on the watch page.
Works with YouTube, Coursera, Udemy and more educational platforms
Get Instant Transcripts: Just Edit the Domain in Your Address Bar!
YouTube
←
→
↻
https://www.youtube.com/watch?v=UF8uR6Z6KLc
YoutubeToText
←
→
↻
https://youtubetotext.net/watch?v=UF8uR6Z6KLc