# Moving a Next.js app from Vercel to Cloud Run

> Vercel builds, caches, schedules and previews a Next.js app; on Cloud Run each is a piece you set up once. When the move pays, the container, secrets, cron, previews, the domain, and both bills.

Published 2026-10-11 · Updated 2026-10-13 · [By Exodus team](https://exodus.elim.io/about) · From Vercel
<https://exodus.elim.io/blog/vercel-to-cloud-run>

Moving a Next.js app from Vercel to Cloud Run takes the standalone output and a 15-line Dockerfile, secrets collected from their sources into Secret Manager, cron jobs turned into Cloud Scheduler jobs, previews into tagged revisions, and the domain behind a load balancer or Firebase Hosting. At 1 million requests and 100 GB a month, Cloud Run costs $10.26 against Vercel Pro's $20 per deploying seat.

## In short

- Vercel Pro is $20 a month per deploying seat with $20 of usage credit and 1 TB of transfer included; Cloud Run has no seats and charges $0.105 per GiB to users in Europe.
- At 10 million requests and 1,000 GB a month the order flips: Cloud Run costs $146.27, Vercel Pro $56.78 for one seat and $96.78 for three.
- A request on Cloud Run may run up to 60 minutes on an instance of up to 32 GiB and 8 vCPU, against Vercel's 800 seconds at most on Pro.
- Vercel cron jobs become Cloud Scheduler jobs at $0.10 a job per 31 days, the first 3 free per billing account, with an OIDC token the route verifies.
- Lower the DNS TTL to 300 seconds a day before the switch, and keep the Vercel project for a week as the way back.

Prices are Vercel's Dublin and Google's Tier 1 list prices, read on October 11, 2026.

## When moving pays, and when it does not

Vercel builds, caches, schedules and previews a Next.js app without anyone writing infrastructure; Cloud Run runs a container and bills for the time it works. The same steps apply to a Remix, SvelteKit or Express app on Vercel; only the container changes, and [moving from Netlify to Cloud Run](https://exodus.elim.io/blog/netlify-to-cloud-run) has its own guide.

Vercel's Hobby plan is free and is for personal, non-commercial use only. Anything that earns money goes on Pro: a $20 platform fee a month that includes one deploying seat and $20 of usage credit, then $20 for every additional seat that deploys. Usage beyond the credit is billed per resource: Active CPU, Provisioned Memory, invocations, data transfer from functions to the CDN, and more. The Pro plan includes 10 million CDN requests and 1 TB of Fast Data Transfer a month, with $0.15 per GB after that in Dublin. (Vercel's Flat Rate CDN page, an option you turn on, sizes the tier included with Pro at 1 million requests and 1 TB; the pricing page's on-demand numbers are what this guide uses.)

Cloud Run has no seats and no platform fee. A service with [request-based billing](https://exodus.elim.io/blog/request-based-or-instance-based-billing) pays $0.000024 per vCPU-second and $0.0000025 per GiB-second while it handles requests, and $0.40 per million requests, after a [free tier](https://exodus.elim.io/blog/the-cloud-run-free-tier-explained) of 180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests a month per billing account (Tier 1 is the price group of regions such as `europe-west1`; prices of October 11, 2026). What it does not include is traffic: every byte to your users is internet egress, $0.105 per GiB within Europe on Cloud Run's own SKU, as the [egress guide](https://exodus.elim.io/blog/egress-on-google-cloud-explained) explains.

So the bill turns on two numbers: how many people deploy, and how many bytes the app sends.

![Six bars: at 1 million requests and 100 GB, Vercel Pro costs $20 with one seat and $60 with three, Cloud Run $10.26; at 10 million requests and 1,000 GB, Vercel Pro costs $56.78 and $96.78, Cloud Run $146.27](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-c17ef917e1c2ed25031fe7b539f9a22512858272fc5dd9386b0c949413e1714f-680x360-svg/bytes "One Next.js app, every request rendered by the server (200 ms, 50 ms of it on the CPU), list prices of October 11, 2026. Both sides are upper bounds: no request shares an instance with another")

The model behind the picture is the same app on both sides. Every request is rendered by the server and takes 200 ms, of which 50 ms is CPU and the rest is waiting on the database. Responses average 100 KB, assets included, and a fifth of the bytes are HTML from the server. On Vercel the functions run in Dublin at the default 2 GB and 1 vCPU; on Cloud Run the service runs in europe-west1 with 1 vCPU and 512 MiB.

- **1 million requests and 100 GB a month.** Vercel's usage comes to $5.68 (invocations $0.60, Active CPU $2.33, memory $1.54, origin transfer $1.20), inside the $20 credit, so the bill is $20 for one seat and $60 for three. Cloud Run charges $0.48 of CPU above the free tier and $9.78 of egress for 93.1 GiB, $10.26 in total, whatever the size of the team.
- **10 million requests and 1,000 GB a month.** Vercel's usage is $56.78, $36.78 above the credit, so the bill is $56.78 for one seat and $96.78 for three; the terabyte is still included. Cloud Run charges $43.68 of CPU, $1.60 of memory, $3.20 of requests and $97.79 of egress: $146.27.

Move when the team is several people on a modest amount of traffic, when a request needs more than Vercel's limits allow (below), or when the rest of your system already lives on Google Cloud. Stay when the app sends a terabyte a month to users and one person deploys it: Vercel's included transfer is worth more than Cloud Run's free tier, and [a VPS with included traffic](https://exodus.elim.io/blog/a-vps-to-cloud-run) may be cheaper than both.

## What Vercel did for you

Before any command, list what Vercel provided, because each item needs a home on Google Cloud. The CLI described at the end does this from your repository; by hand, open `vercel.json`, `next.config.*`, `package.json` and the project's settings page side by side.

![Seven pairs: Functions and SSR become a Cloud Run service; the CDN for static files becomes the same container, with Cloud CDN later if needed; Cron Jobs become Cloud Scheduler; environment variables become env vars and Secret Manager; preview deployments become revision tags; domains and certificates go to a load balancer or Firebase Hosting; Marketplace storage stays where it is](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-48cdf971f6e8b4b6bbdbd4427b23140e388ca72a30024b0ccdca9f6db158a6b6-680x504-svg/bytes "Where each part of a Vercel project goes on Google Cloud")

Two of these surprise people. Static files: on Vercel, `_next/static` and `public/` are deployed to every CDN region, while your functions run in one region, `iad1` (Washington, D.C.) unless you changed it. On Cloud Run the same container serves both from one region. That is fine for most apps, because the files carry long cache headers and browsers keep them, but a site with a global audience and heavy pages may want Cloud CDN in front later. Storage: Vercel Postgres and Vercel KV moved to the Marketplace, so the database is a Neon, Supabase or Upstash account with a connection string. It does not move with the app. Point the Cloud Run service at the same database first and decide about Cloud SQL later; the [Cloud SQL guide](https://exodus.elim.io/blog/cloud-sql-smallest-instances-and-what-they-cost) has the prices.

## Step 1: put the app in a container

Next.js can produce a self-contained server. Add one line to `next.config.ts`:

```ts
const nextConfig: NextConfig = {
  output: "standalone",
};
```

`next build` then writes `.next/standalone` with a minimal `server.js` and only the parts of `node_modules` the app uses. It does not copy `public/` or `.next/static`, because Next.js assumes a CDN serves them; the Dockerfile copies them in. Put this `Dockerfile` in the repository root:

```dockerfile
FROM node:24-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:24-slim
WORKDIR /app
ENV NODE_ENV=production PORT=8080 HOSTNAME=0.0.0.0
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
USER node
CMD ["node", "server.js"]
```

And a `.dockerignore`, so local builds and secrets stay out of the image:

```
node_modules
.next
.git
.env*.local
```

`HOSTNAME=0.0.0.0` matters: without it the server listens only inside the container and Cloud Run's health check never reaches it. `PORT=8080` is Cloud Run's default. If you use pnpm or yarn, copy that lockfile and use its install command instead of `npm ci`.

Build and run it before anything touches Google:

```shell
docker build -t helloworld .
docker run --rm -p 8187:8080 helloworld
```

![A terminal: docker run starts Next.js 16.4.0 on port 8080, ready in 0 ms; curl to / returns 200 and curl to /api/cron without a token returns 401](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-0a2492d5031bb91f680361de3092e3f6ae9e0845f14d3184f690c8c0dfc35376-680x296-svg/bytes "The sample app from this guide in its container on our machine, October 11, 2026: the page answers, the cron route refuses a call without a token")

We built a fresh `create-next-app@16` project with exactly these files, added the cron route from Step 4, and got the output above. You can also skip the Dockerfile: `gcloud run deploy --source .` builds a Next.js app with Google's buildpacks, which run `npm run build` and start with `npm start`. The Dockerfile is worth the 15 lines, because you see and test exactly what runs. The [buildpacks or a Dockerfile guide](https://exodus.elim.io/blog/buildpacks-or-a-dockerfile) compares the two.

## Step 2: move the environment variables

This is the step that stalls moves. On Vercel, Production and Preview variables are created as the Secret type by default, and a Secret value is write-only after saving. `vercel env pull --environment=production` cannot give them back. The values of your secrets have to come from where they were made: the database provider's dashboard, the payment provider, the OAuth app. Make the list from the project's settings page before the move day, and get each value from its source.

Then sort the variables into three kinds:

- **Variables starting with** `NEXT_PUBLIC_` are inlined into the JavaScript bundle by `next build`. They must exist at build time, and they are public anyway. Put them in `.env.production` in the repository; Next.js reads that file during the build. We checked this on the sample: a page that prints `NEXT_PUBLIC_SITE_NAME` from `.env.production` showed the value in the container.
- **Plain configuration** (a feature flag, an API base URL) goes on the service with `--set-env-vars`.
- **Secrets** (database URL, API keys, signing keys) go to Secret Manager, Google's store for secrets. Each becomes an environment variable when the container starts; [secrets on Cloud Run](https://exodus.elim.io/blog/secrets-on-cloud-run) covers versions and rotation.

Create a service account for the app (a Google identity for a program, not a person), then each secret, typing or pasting the value on standard input so it never appears in your shell history (finish with Ctrl-D):

```shell
gcloud iam service-accounts create web
gcloud secrets create DATABASE_URL --data-file=-
gcloud secrets add-iam-policy-binding DATABASE_URL \
  --member=serviceAccount:web@PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/secretmanager.secretAccessor
```

Vercel also injected system variables such as `VERCEL_URL` and `VERCEL_ENV`. Search the code for `VERCEL_`; anything that reads them needs its own variable on Cloud Run.

## Step 3: deploy

Pick the region first, because it should sit next to the database, not next to you. Vercel's default `iad1` is in Washington, D.C.; if the database is in AWS `us-east-1`, the Cloud Run region nearest to it is `us-east4` (Northern Virginia). For a European database, `europe-west1` (Belgium) is a Tier 1 region. The [region guide](https://exodus.elim.io/blog/choosing-a-cloud-run-region) covers the trade-offs.

```shell
gcloud run deploy web --source . --region europe-west1 \
  --service-account=web@PROJECT_ID.iam.gserviceaccount.com \
  --allow-unauthenticated \
  --set-env-vars=API_BASE_URL=https://api.example.com \
  --set-secrets=DATABASE_URL=DATABASE_URL:latest
```

With a Dockerfile in the directory, `--source .` sends the code to Cloud Build, builds that Dockerfile, stores the image in an Artifact Registry repository named `cloud-run-source-deploy`, and deploys it. The first run asks to enable APIs and to create the repository; answer yes. At the end it prints the service URL, `https://web-PROJECT_NUMBER.europe-west1.run.app`.

Two settings differ from Vercel's defaults. A request on Cloud Run may run 5 minutes by default and up to 60 with `--timeout=3600`, against Vercel's 300 seconds, 800 at most on Pro. An instance can have up to 32 GiB and 8 vCPU, and handles many requests at once instead of one.

![A table of limits on Vercel Pro and Cloud Run: longest request, memory and CPU, request body, cron, server regions, static files](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-15a57cf9793a63b1b58e922c88182b910c03b89b3a29f73180b96c577d909bc4-680x408-svg/bytes "The limits that change in a move, from Vercel's and Google's pages of October 11, 2026")

## Step 4: what changes inside Next.js

Most of a Next.js app runs on `next start` (or the standalone `server.js`) unchanged. Image optimization through `next/image` works with no configuration, using `sharp` in the container. Proxy (the file formerly called middleware) runs in the server too. Redirects, rewrites and headers in `vercel.json` do not: nothing reads that file on Cloud Run, so move them into `next.config.ts` (`redirects()`, `rewrites()`, `headers()`), where Next.js applies them itself.

Five things behave differently, because Cloud Run runs several copies of the same container and Vercel's platform no longer stands behind them:

- **The ISR (incremental static regeneration) and data cache is per instance.** By default Next.js keeps it in memory (50 MB) and on the local disk of each server. On Cloud Run the disk is memory and goes away with the instance, so two instances can serve different versions of a revalidated page, and a `revalidatePath` reaches only the instance that ran it. For pages that revalidate rarely, accept it. Otherwise configure a `cacheHandler` that stores the cache in Redis or a bucket, as the self-hosting guide shows.
- **Server Functions keys are per build.** Next.js encrypts Server Function closures with a key generated at build time. All instances of one Cloud Run revision run the same image, so they share it. Between revisions they do not, so a page loaded from the old revision can fail with "Failed to find Server Action" after a deploy. Setting `deploymentId` in `next.config.ts` lets Next.js detect this version skew and reload instead.
- **Work after the response stops.** Next.js `after()` and Vercel's `waitUntil` run code after the response is sent. On Cloud Run with request-based billing, CPU is only allocated while a request is being processed, so that code crawls or never finishes. Send it to Cloud Tasks (a queue that calls your service later), or switch the service to instance-based billing; the [billing guide](https://exodus.elim.io/blog/request-based-or-instance-based-billing) explains the cost.
- **Cold starts are yours.** A service with no traffic scales to zero, and the next request waits for a container to start. `--min-instances=1` keeps one ready, billed at the idle rate.
- **Vercel's own packages.** Packages under `@vercel/` were written for Vercel's platform. Search `package.json` for them and check in each one's documentation what it does outside Vercel; replace or remove the ones that only work there.

## Step 5: cron jobs become Cloud Scheduler

A Vercel cron job is an entry in `vercel.json` with a `path` and a `schedule`; Vercel sends an HTTP GET to the production URL at that time, in UTC, with your `CRON_SECRET` as a Bearer token. Cloud Scheduler does the same with any HTTP method, in any time zone, and instead of a shared secret it sends an OpenID Connect token, a statement of who is calling signed by Google, for a service account you name. It costs $0.10 a job per 31 days, and the first 3 jobs on a billing account are free.

Because the service is public (`--allow-unauthenticated`), Cloud Run does not check that token for you: anyone can call `/api/cron`. The route has to verify it, which replaces the `CRON_SECRET` comparison:

```ts
import { OAuth2Client } from "google-auth-library";

const client = new OAuth2Client();

export async function GET(request: Request) {
  const token = request.headers.get("authorization")?.replace("Bearer ", "");
  if (!token) return new Response("Unauthorized", { status: 401 });
  try {
    const ticket = await client.verifyIdToken({
      idToken: token,
      audience: process.env.CRON_AUDIENCE,
    });
    if (ticket.getPayload()?.email !== process.env.CRON_INVOKER) {
      return new Response("Forbidden", { status: 403 });
    }
  } catch {
    return new Response("Unauthorized", { status: 401 });
  }
  // the work the Vercel cron did
  return Response.json({ ok: true });
}
```

`verifyIdToken` checks Google's signature, the expiry and the audience; the email check makes sure the token belongs to your scheduler's service account and not to any other Google identity. Install it with `npm install google-auth-library`. Then create the account and the job, with the same schedule as in `vercel.json`:

```shell
gcloud iam service-accounts create cron
gcloud scheduler jobs create http nightly-report \
  --location=europe-west1 \
  --schedule="0 5 * * *" \
  --http-method=GET \
  --uri=https://web-PROJECT_NUMBER.europe-west1.run.app/api/cron \
  --oidc-service-account-email=cron@PROJECT_ID.iam.gserviceaccount.com \
  --oidc-token-audience=https://web-PROJECT_NUMBER.europe-west1.run.app/api/cron
gcloud run services update web --region europe-west1 \
  --update-env-vars=CRON_AUDIENCE=https://web-PROJECT_NUMBER.europe-west1.run.app/api/cron,CRON_INVOKER=cron@PROJECT_ID.iam.gserviceaccount.com
```

`--http-method=GET` is needed because Cloud Scheduler sends POST by default, and a route that exports only `GET` would answer 405. The time zone defaults to UTC, as on Vercel; `--time-zone=Europe/Berlin` changes it. A job that runs longer than an HTTP request should become a Cloud Run job started by the scheduler; the [services, jobs and worker pools guide](https://exodus.elim.io/blog/cloud-run-services-jobs-and-worker-pools) shows when.

## Step 6: preview deployments

On Vercel, every push to a branch gets its own URL. Cloud Run's equivalent is a revision with a tag and no traffic:

```shell
gcloud run deploy web --source . --region europe-west1 --no-traffic --tag pr-12
```

The new revision gets its own URL, `https://pr-12---web-HASH.a.run.app`, while production keeps 100% of the traffic. There is a catch Vercel hid from you. Vercel previews had their own Preview variables; a tagged revision inherits the service's configuration, so it reads the production secrets and writes to the production database. For anything more than a visual check, deploy previews to a second service, `web-staging`, with its own secrets and its own database, and tag revisions there.

To deploy on every push, connect the repository to Cloud Build from the Cloud Run page ("continuous deployment"), or run the same `gcloud run deploy` from your CI. If what you want is Vercel's workflow on Google's infrastructure, Google's own Next.js quickstart points to Firebase App Hosting: it connects to GitHub, builds with Cloud Build on every push to a branch, serves from Cloud Run and caches in Cloud CDN, all in your project.

## Step 7: the domain and the switch

Google gives three ways to put your domain on a Cloud Run service. A global external Application Load Balancer is the one Google recommends: your own certificates, path routing, a CDN cache (Cloud CDN) and a web firewall (Cloud Armor), with a forwarding rule, the entry point, at $0.025 an hour, about $18.25 a month. Firebase Hosting can also front the service and hold the domain. Cloud Run's own domain mapping is the simplest, but it is in Preview, Google says it is not production-ready because of latency issues, and it exists in only 10 regions.

The switch itself, in order:

1. A day before, lower the TTL of the DNS records you will change (the time resolvers keep a record) to 300 seconds, so the change spreads and can be undone quickly.
1. Deploy to Cloud Run and test on the `run.app` URL: sign-in, a payment in test mode, a form, a page with images, the cron route with a manual run of the scheduler job (`gcloud scheduler jobs run nightly-report --location=europe-west1`).
1. If the app signs users in with OAuth, add the new domain's callback URL to the provider while the old one still works.
1. Set up the load balancer or Firebase Hosting and wait until its certificate is active.
1. Change the DNS records. Watch the logs in the Cloud Run console and the error rate for an hour.
1. Disable the cron jobs on Vercel (remove them from `vercel.json` and deploy), so they do not run twice.
1. Keep the Vercel project for a week as the way back, then delete it.

The database does not move, so there is no data to copy.

## What breaks most often

From the limits and the platform differences above, the failures cluster in a few places:

- The container listens on `localhost` (no `HOSTNAME=0.0.0.0`) and the first deploy fails its health check.
- A secret was never copied, because `vercel env pull` returned it empty, and the app fails on its first database call.
- A `NEXT_PUBLIC_` value was set on the Cloud Run service instead of at build time, and the browser sees `undefined`.
- Redirects from `vercel.json` silently stop working, because nothing reads the file.
- Emails or webhooks sent in `after()` arrive late or never.
- A preview revision writes to the production database.
- Requests from users far away are slower, because the static files no longer come from a CDN near them.

Every one of these is visible in the `run.app` test of step 2 of the switch, before users see it. The [patterns that break on Cloud Run](https://exodus.elim.io/blog/patterns-that-break-on-cloud-run) guide covers the rest: in-process queues, files on disk, sessions in memory.

## Where Exodus comes in

Exodus's CLI reads `vercel.json`, `next.config.*` and `package.json` on your machine, with your coding agent reading the code for the ambiguous parts. The report lists each piece from the picture above with what it becomes: the cron entries with their schedules turned into scheduler jobs, the routes that use `after()` or `waitUntil`, the `@vercel/` packages, the variables the code reads with a note on which are build-time, and whether ISR needs a shared cache. It then estimates the month on Cloud Run for your traffic next to what you pay Vercel now, egress included, and says plainly when staying is cheaper.

## FAQ

### Is Cloud Run cheaper than Vercel?

It depends on how many people deploy and how many bytes the app sends. At 1 million requests and 100 GB a month, Cloud Run costs $10.26 against $20 for one Vercel Pro seat and $60 for three. At 10 million requests and 1,000 GB, Vercel's included terabyte wins: $56.78 for one seat against $146.27 on Cloud Run.

### Can I export secret environment variables from Vercel?

No. Production and Preview variables are created as the Secret type by default, and a Secret value is write-only after saving, so vercel env pull returns it empty. Get each value from where it was made: the database provider's dashboard, the payment provider, the OAuth app. Make the list from the project's settings page before the move day.

### Does next/image work on Cloud Run?

Yes. Image optimization works with no configuration, using sharp in the container, and Proxy, the file formerly called middleware, runs in the server too. Redirects, rewrites and headers in vercel.json do not, because nothing reads that file on Cloud Run; move them into next.config.ts.

### How do I get Vercel preview deployments on Cloud Run?

Deploy a revision with no traffic and a tag: it gets its own URL while production keeps 100% of the traffic. A tagged revision inherits the service's configuration, so it reads the production secrets and writes to the production database; for more than a visual check, deploy previews to a second staging service with its own secrets and database.

## Sources

1. [Vercel pricing (Hobby for personal, non-commercial use; Pro $20 a month with $20 of usage credit; $20 per extra deploying seat; 10M CDN requests and 1 TB of Fast Data Transfer included, then from $2 per 1M and $0.15 per GB; invocations from $0.60 per 1M; read Oct 11, 2026)](https://vercel.com/pricing)
2. [Vercel Pro plan (the $20 platform fee includes one deploying seat and $20 of monthly usage credit; read Oct 11, 2026)](https://vercel.com/docs/plans/pro-plan)
3. [Vercel Hobby plan (non-commercial, personal use only; read Oct 11, 2026)](https://vercel.com/docs/plans/hobby)
4. [Vercel Flat Rate CDN (the tier included with Pro is 1M CDN requests and 1 TB of data transfer; read Oct 11, 2026)](https://vercel.com/docs/pricing/flat-rate-cdn)
5. [Vercel regional pricing, Dublin dub1 (Fluid Active CPU $0.168 an hour, Provisioned Memory $0.0139 per GB-hour, Fast Origin Transfer $0.06 per GB, Fast Data Transfer $0.15 per GB; read Oct 11, 2026)](https://vercel.com/docs/pricing/regional-pricing/dub1)
6. [Fluid compute pricing, Vercel (Active CPU only while code runs, Provisioned Memory while requests are in flight; read Oct 11, 2026)](https://vercel.com/docs/functions/usage-and-pricing)
7. [Vercel Functions limits (300 s default, 800 s maximum, 1,800 s in beta on Pro; 2 GB and 1 vCPU default, 4 GB and 2 vCPU maximum; 4.5 MB request and response body; read Oct 11, 2026)](https://vercel.com/docs/functions/limitations)
8. [Fluid compute, Vercel (multi-region functions: up to 3 on Pro; read Oct 11, 2026)](https://vercel.com/docs/fluid-compute)
9. [vercel.json reference (regions default to iad1; static files are deployed to every region; rewrites, redirects, headers, crons; read Oct 11, 2026)](https://vercel.com/docs/project-configuration/vercel-json)
10. [Cron jobs, Vercel (an HTTP GET to the production URL, user agent vercel-cron/1.0, UTC only; read Oct 11, 2026)](https://vercel.com/docs/cron-jobs)
11. [Cron jobs usage and pricing, Vercel (Hobby once a day with a precision of an hour, Pro once a minute; read Oct 11, 2026)](https://vercel.com/docs/cron-jobs/usage-and-pricing)
12. [Managing cron jobs, Vercel (CRON_SECRET sent as a Bearer Authorization header; read Oct 11, 2026)](https://vercel.com/docs/cron-jobs/manage-cron-jobs)
13. [Config and Secret environment variables, Vercel (Secret values are write-only after saving; read Oct 11, 2026)](https://vercel.com/docs/environment-variables/sensitive-environment-variables)
14. [vercel env, Vercel CLI (Production and Preview variables default to the Secret type; vercel env pull; read Oct 11, 2026)](https://vercel.com/docs/cli/env)
15. [Storage on the Vercel Marketplace (Postgres from Neon, Supabase and others, Redis from Upstash; credentials injected as environment variables; read Oct 11, 2026)](https://vercel.com/docs/marketplace-storage)
16. [How to self-host your Next.js application, Next.js 16.4 docs (image optimization and Proxy work with next start; NEXT_PUBLIC_ values inlined at build; ISR cache per instance and cacheHandler; Server Functions key per build; deploymentId; read Oct 11, 2026)](https://nextjs.org/docs/app/guides/self-hosting)
17. [output: standalone, Next.js docs (.next/standalone with server.js; public and .next/static copied by hand; PORT and HOSTNAME; read Oct 11, 2026)](https://nextjs.org/docs/app/api-reference/config/next-config-js/output)
18. [after, Next.js docs (a callback run after the response; on serverless platforms it needs waitUntil; read Oct 11, 2026)](https://nextjs.org/docs/app/api-reference/functions/after)
19. [Quickstart: build and deploy a Next.js web app to Cloud Run, Google (gcloud run deploy --source .; Firebase App Hosting suggested for GitHub integration and a CDN; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/quickstarts/frameworks/deploy-nextjs-service)
20. [Deploy services from source code, Cloud Run (a Dockerfile is used if present, otherwise buildpacks; images in the cloud-run-source-deploy repository; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/deploying-source-code)
21. [Firebase App Hosting, Google (built with Cloud Build, served on Cloud Run, cached in Cloud CDN, deployed on push to a branch; read Oct 11, 2026)](https://firebase.google.com/docs/app-hosting)
22. [Cloud Run pricing, Google (request-based billing in Tier 1: $0.000024 per vCPU-second, $0.0000025 per GiB-second, $0.40 per million requests; free 180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests a month; read Oct 11, 2026)](https://cloud.google.com/run/pricing)
23. [Billing settings, Cloud Run (with request-based billing CPU is only allocated during request processing; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/configuring/billing-settings)
24. [Cloud Run quotas and limits (32 GiB and 8 vCPU per instance; 60 minute request timeout; 32 MiB HTTP/1 request size, no limit on HTTP/2; read Oct 11, 2026)](https://docs.cloud.google.com/run/quotas)
25. [Request timeout, Cloud Run (5 minutes by default, up to 60; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/configuring/request-timeout)
26. [System environment variables, Vercel (VERCEL_URL, VERCEL_ENV and others set by the platform; read Oct 11, 2026)](https://vercel.com/docs/environment-variables/system-environment-variables)
27. [Migrating from middleware to proxy, Next.js docs (the middleware file convention is deprecated and renamed to proxy; read Oct 11, 2026)](https://nextjs.org/docs/messages/middleware-to-proxy)
28. [Continuous deployment from Git, Cloud Run (connect a repository through Cloud Build from the service page; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/continuous-deployment)
29. [Rollouts, rollbacks and traffic migration, Cloud Run (--no-traffic --tag; a tagged revision at https://TAG---SERVICE-HASH.a.run.app; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/rollouts-rollbacks-traffic-migration)
30. [Cloud Scheduler pricing, Google ($0.10 a job per 31 days; 3 jobs free per billing account; read Oct 11, 2026)](https://cloud.google.com/scheduler/pricing)
31. [Use authentication with HTTP targets, Cloud Scheduler (OIDC tokens, audience; a target that does not check IAM must verify the token itself; read Oct 11, 2026)](https://docs.cloud.google.com/scheduler/docs/http-target-auth)
32. [Running services on a schedule, Cloud Run (gcloud scheduler jobs create http with an OIDC service account and the run.invoker role; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/triggering/using-scheduler)
33. [Map custom domains, Cloud Run (global external Application Load Balancer recommended; Firebase Hosting; Cloud Run domain mapping in Preview, not production-ready, in 10 regions; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/mapping-custom-domains)
34. [Cloud Load Balancing pricing, Google (first 5 forwarding rules $0.025 an hour; read Oct 11, 2026)](https://cloud.google.com/load-balancing/pricing)
35. [Cloud Run locations, Google (43 regions in gcloud run regions list, Oct 11, 2026)](https://docs.cloud.google.com/run/docs/locations)
36. Exodus team: a Next.js 16.4 sample built with the Dockerfile in this guide and run with Docker on Oct 11, 2026; the cost model and its arithmetic
