# Moving a Netlify site to Firebase Hosting and Cloud Run

> A Netlify site moves to Firebase Hosting for files and one Cloud Run service for code. An adapter for unchanged functions, _redirects as firebase.json, schedules, secrets, the domain, both bills.

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

A Netlify site moves to Google Cloud in two parts: the built files go to Firebase Hosting, and the functions go to one Cloud Run service that Hosting reaches through a rewrite, so visitors still see one site on one domain. The functions run unchanged through a 50-line adapter. In our model a small site costs $14 a month on Netlify and $3 on Google.

## In short

- Firebase Hosting stores 10 GB and sends 10 GB a month at no cost, then $0.15 per GB sent; a site without functions needs nothing else.
- Our model: a small site $14 on Netlify against $3, a medium one $53 against $43.50, a large one $456 against $458.98; bandwidth dominates every case.
- Requests through Firebase Hosting stop at 60 seconds and carry only the `__session` cookie; the `run.app` URL allows 60 minutes.
- Scheduled functions, 30 seconds at most, become Cloud Run jobs started by Cloud Scheduler; background functions, 15 minutes, become Cloud Tasks, up to 30.

Prices are list prices of October 11, 2026, with the cheapest plan and packs on Netlify.

## When moving pays, and when it does not

Netlify moved to credit-based plans on September 4, 2025; teams created before that date keep their Legacy plan unless they switch. On the current plans, Free gives 300 credits a month and pauses the site when they run out. Personal is $9 for 1,000 credits and is meant for one developer. Pro is $20 for 3,000 credits with unlimited members, and larger Pro tiers go up to 20,000 credits for $126. Extra credits come in packs: $5 per 500 on Personal, $10 per 1,500 on Pro.

Every meter draws on those credits. A production deploy costs 15 credits, a GB of bandwidth 20, a GB-hour of function compute 10, and 10,000 web requests 2 (page views, assets, function calls and redirects all count). Deploy Previews and branch deploys are free. At the Pro pack rate a credit is $0.0067, so a GB of bandwidth is about $0.13 and a production deploy about $0.10.

On Google's side, Firebase Hosting on the pay-as-you-go plan (Blaze) stores 10 GB and sends 10 GB a month at no cost, then charges $0.026 per GB stored and $0.15 per GB sent. Cloud Run with [request-based billing](https://exodus.elim.io/blog/request-based-or-instance-based-billing) charges $0.000024 per vCPU-second, $0.0000025 per GiB-second 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 (Tier 1 regions such as `europe-west1`, prices of October 11, 2026). There is no charge per deploy and none per seat.

![Six bars: a small site costs $14 on Netlify and $3 on Firebase Hosting with Cloud Run; a medium site $53 and $43.50; a large site $456 and $458.98](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-139e11aec4e078c94d69ce451894f736d1f5e38ac278689059723f35af63bb18-680x360-svg/bytes "One content site with a few functions on Netlify's credit plans and on Firebase Hosting plus Cloud Run, list prices of October 11, 2026, cheapest plan and packs on Netlify")

The model behind the picture is one site in three sizes. Functions run 200 ms per call, at Netlify's default 1 GB and on Cloud Run at 1 vCPU and 512 MiB, counted as if no two calls shared an instance.

- **Small:** 300,000 web requests, 30 GB sent, 30,000 function calls and 40 production deploys a month. That is 1,277 credits: Personal plus one pack, $14. Google charges $3.00 for 20 GB of Hosting transfer above the free 10, and the function calls fit in Cloud Run's free tier.
- **Medium:** 3 million requests, 300 GB, 300,000 calls, 60 deploys: 7,667 credits, cheapest as Pro 5,000 plus two packs, $53. Google: $43.50, all of it Hosting transfer.
- **Large:** 30 million requests, 3,000 GB, 3 million calls, 100 deploys: 69,167 credits, Pro 20,000 plus 33 packs, $456. Google: $448.50 of transfer, $10.08 of CPU and $0.40 of requests, $458.98.

Bandwidth dominates every case, and the two providers price it about the same. Deploys are what tip the small site: 40 of them are 600 of its 1,277 credits. A large site that wants a lower bill on Google puts its files in a Cloud Storage bucket behind a load balancer with Cloud CDN instead of Firebase Hosting: cache egress to Europe is $0.08 per GiB, and the same large site comes to about $280 a month with the load balancer ($18.25), cache lookups and fills included. On a Legacy Pro plan the arithmetic is different again: 1 TB is included and each further 100 GB costs $55.

So price alone rarely decides it. Move when the functions outgrow Netlify's limits (a request that needs more than 60 seconds, an upload above 6 MB, a job longer than 15 minutes), when the database and the rest of the system already live on Google Cloud, or when the team deploys to production many times a day.

## What Netlify did for you

A Netlify site is four things that arrive together: a folder of built files served from a CDN, a few functions in `netlify/functions`, routing rules in `_redirects` and `netlify.toml`, and platform features such as forms, previews and a domain with a certificate. Google Cloud has no single product that does all four.

Open `netlify.toml`, the `_redirects` and `_headers` files in the publish directory, the `netlify/functions` folder and the site's settings page, and list every piece. Each one needs a home.

![Eleven pairs: the publish directory and CDN become Firebase Hosting; _redirects and _headers become firebase.json; functions become one Cloud Run service; scheduled functions become a Cloud Run job started by Cloud Scheduler; background functions become Cloud Tasks or a job; Edge Functions become code in the service; Forms become a route and your database; Identity becomes Firebase Authentication; environment variables become env vars and Secret Manager; Deploy Previews become preview channels; the domain moves to Firebase Hosting](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-a02a8bdf02a488751c152a6fd12c0ddf3ded63a62b184f904106507290c2e6bc-680x728-svg/bytes "Where each part of a Netlify site goes on Google Cloud")

Two pieces have no direct equivalent. Edge Functions run in Deno at Netlify's edge, with 50 ms of CPU per request; Google Cloud has no direct equivalent for your own code, so their logic moves into the Cloud Run service, which runs in one region. Netlify Image CDN (`/.netlify/images`) resizes images on request; on Google you resize at build time or in your own code.

## Step 1: the files go to Firebase Hosting

Install the Firebase CLI (`npm install -g firebase-tools`), sign in, and add Firebase to your Google Cloud project from the Firebase console. Then put a `firebase.json` in the repository root that points at the same publish directory Netlify used:

```json
{
  "hosting": {
    "public": "public",
    "ignore": ["firebase.json", "**/.*", "_redirects", "_headers"],
    "cleanUrls": true
  }
}
```

Netlify built the site for you; Firebase Hosting does not build. Run the same build command from `netlify.toml` (`npm run build`) on your machine or in CI, then `firebase deploy --only hosting`. Every deploy is kept as a version, and a rollback is one click in the console. If the site has no functions, Hosting alone serves the files, the redirects and the domain, and the Cloud Run steps below do not apply.

`cleanUrls` makes `/about.html` answer at `/about` and redirects the `.html` form there, which is what Netlify's Pretty URLs did. Trailing slashes are the other difference to check: Firebase uses them only for directory index files unless you set `trailingSlash`, so compare a few of your URLs on both before the switch.

## Step 2: `_redirects` and `_headers` become `firebase.json`

Netlify reads `_redirects` first and `netlify.toml` second, and the first matching rule wins. A rule does not apply when a file exists at that path unless you force it with `!`. Firebase has a fixed order: redirects, then exact static files, then rewrites. So a Firebase redirect always wins over a file, as a forced Netlify rule did, and a Firebase rewrite never shadows a file, as an unforced Netlify rewrite did not.

Here is a typical `_redirects` and its translation:

```
/blog/*      /posts/:splat              301
/api/*       /.netlify/functions/:splat 200
/*           /index.html                200
```

```json
"redirects": [
  { "source": "/blog/:rest*", "destination": "/posts/:rest", "type": 301 }
],
"rewrites": [
  { "source": "/api/**", "run": { "serviceId": "shop-api", "region": "europe-west1" } },
  { "source": "**", "destination": "/index.html" }
],
"headers": [
  { "source": "/assets/**",
    "headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }] }
]
```

A splat becomes a capture with `*` (`:rest*`), a status of 200 becomes a rewrite, and the single-page fallback becomes a rewrite of `**` to `/index.html`. We ran this file in the Firebase Hosting emulator against a sample site:

![A terminal: curl against the Firebase Hosting emulator shows /blog/first redirected with 301 to /posts/first, /posts/first.html redirected to /posts/first, a client route answered 200 by the fallback, and /assets/app.css served with the immutable Cache-Control header](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-7388d42ae8f22d35052845b8c23e512c0d38df04015d8902d7058f27029f89fd-680x340-svg/bytes "The translated rules in the Firebase Hosting emulator, October 11, 2026")

Three kinds of Netlify rule do not translate. Conditions on country, language, role or cookie have no field in `firebase.json`; that logic moves into the Cloud Run service. A proxy to another site (`/search https://api.example.com 200`) has no equivalent, because a Firebase rewrite can only point at a file, a function or a Cloud Run service; call the other API from your service instead. Signed proxy redirects go the same way.

## Step 3: the functions become one Cloud Run service

A modern Netlify function is a file whose default export takes a web `Request` and returns a `Response`. Node.js has had both built in since version 18, so the functions can run unchanged inside an ordinary HTTP server. The adapter below loads every file in `netlify/functions`, routes `/.netlify/functions/NAME` and any `config.path` (with parameters such as `/api/orders/:id`), supports older Lambda-style `exports.handler` functions, and skips scheduled ones. Save it as `server.mjs` in the repository root:

```ts
import http from "node:http";
import { readdirSync } from "node:fs";

const dir = new URL("./netlify/functions/", import.meta.url);
const prefix = process.env.API_PREFIX; // /api, if _redirects sent /api/* to functions
const routes = [];
for (const file of readdirSync(dir).filter((f) => /\.[cm]?js$/.test(f))) {
  const name = file.replace(/\.[cm]?js$/, "");
  const mod = await import(new URL(file, dir));
  const cfg = mod.config ?? mod.default?.config ?? {};
  if (cfg.schedule) continue; // runs as a Cloud Run job, Step 5
  const paths = cfg.path ? [cfg.path].flat()
    : [`/.netlify/functions/${name}`, ...(prefix ? [`${prefix}/${name}`] : [])];
  for (const p of paths) routes.push({ pattern: new URLPattern({ pathname: p }), mod });
}

http.createServer(async (req, res) => {
  try {
    const url = new URL(req.url, `http://${req.headers.host}`);
    const route = routes.find((r) => r.pattern.test(url));
    if (!route) return res.writeHead(404).end("not found");
    const params = route.pattern.exec(url).pathname.groups;
    const body = ["GET", "HEAD"].includes(req.method) ? undefined : Buffer.concat(await req.toArray());
    const headers = new Headers();
    for (const [k, v] of Object.entries(req.headers)) for (const x of [v].flat()) headers.append(k, x);
    let response;
    if (route.mod.handler) {
      const r = await route.mod.handler({
        httpMethod: req.method, path: url.pathname, headers: req.headers, rawUrl: url.href,
        queryStringParameters: Object.fromEntries(url.searchParams),
        body: body?.toString("base64") ?? null, isBase64Encoded: Boolean(body),
      }, {});
      response = new Response(r.isBase64Encoded ? Buffer.from(r.body, "base64") : r.body,
        { status: r.statusCode, headers: r.headers });
    } else {
      const fn = route.mod.default.fetch ?? route.mod.default;
      response = (await fn(new Request(url, { method: req.method, headers, body }), { params }))
        ?? new Response(null, { status: 204 });
    }
    const out = Object.fromEntries(response.headers);
    const cookies = response.headers.getSetCookie();
    if (cookies.length) out["set-cookie"] = cookies;
    res.writeHead(response.status, out).end(Buffer.from(await response.arrayBuffer()));
  } catch (err) {
    console.error(err);
    res.writeHead(500).end("error");
  }
}).listen(process.env.PORT ?? 8080, () => console.log(`${routes.length} routes on :${process.env.PORT ?? 8080}`));
```

The `context` object your functions receive holds only `params`. If they read `context.geo`, `context.ip` or `context.cookies`, replace those with the request's headers. `URLPattern` needs Node.js 24. TypeScript functions need a build step first (`tsc` or `esbuild` into `.mjs`).

The container is short:

```dockerfile
FROM node:24-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY netlify/functions ./netlify/functions
COPY server.mjs run.mjs ./
ENV NODE_ENV=production
USER node
CMD ["node", "server.mjs"]
```

Add a `.dockerignore` with `node_modules`, `.netlify` and `.env*`, then try it before anything touches Google:

```shell
docker build -t shop-api .
docker run --rm -e API_PREFIX=/api -p 8188:8080 shop-api
```

![A terminal: docker run starts the adapter with 5 routes; curl to /api/hello returns hello netlify, a POST to /api/orders/42 returns the order id, the Lambda-style legacy function answers, the scheduled function nightly returns 404 because it is not served over HTTP, and run.mjs runs it once as the job will](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-38f9cccea012eaa21070b8a1a9e63d8a518e3c7ff265cc4383cf0bc24229a296-680x340-svg/bytes "Four sample Netlify functions, two styles, running unchanged in one container on our machine, October 11, 2026")

Then deploy. `--source .` builds the Dockerfile with Cloud Build and stores the image in Artifact Registry:

```shell
gcloud run deploy shop-api --source . --region europe-west1 \
  --allow-unauthenticated --set-env-vars=API_PREFIX=/api
```

The service has to be public, because Firebase Hosting calls it as an anonymous visitor would. Put it in a region Firebase Hosting can rewrite to (Firebase's Cloud Run page lists them) and that sits near your database. Then `firebase deploy --only hosting` makes `/api/**` on your site reach the service.

Two limits come with that path. A request through Firebase Hosting times out after 60 seconds, whatever the service allows, the same as Netlify's synchronous limit; a longer request has to call the `run.app` URL directly, where the limit is 60 minutes, as the [timeouts guide](https://exodus.elim.io/blog/long-requests-and-timeouts) explains with the other clocks on the way. And Hosting strips every cookie except one named `__session` before it reaches the service, so a function that reads a session cookie by another name must rename it. Responses from the service are not cached unless they send `Cache-Control: public` with `s-maxage`.

## Step 4: environment variables and secrets

Netlify can export variables: `netlify env:list --plain --context production` prints them in `.env` format. But a variable marked as containing secret values is write-only and comes back masked in every context except `dev`, so its value has to come from where it was made: the payment provider, the database, the OAuth app.

Plain settings go on the service with `--set-env-vars`. Secrets go to Secret Manager, typed on standard input so they never reach your shell history (finish with Ctrl-D):

```shell
gcloud secrets create STRIPE_KEY --data-file=-
gcloud run services update shop-api --region europe-west1 \
  --set-secrets=STRIPE_KEY=STRIPE_KEY:latest
```

The service runs as the default compute service account unless you name another, and that account needs `roles/secretmanager.secretAccessor` on each secret. The [Vercel guide](https://exodus.elim.io/blog/vercel-to-cloud-run) shows a dedicated service account for the app. Variables Netlify set for you, such as `CONTEXT`, `URL` and `DEPLOY_PRIME_URL`, do not exist on Cloud Run; search the code for them.

## Step 5: scheduled and background functions

A scheduled function runs on Netlify for at most 30 seconds, in UTC, and only on the published deploy. On Google it becomes a Cloud Run job, a container that runs to completion, started by Cloud Scheduler. The same image does it with a different command. Move any `schedule` from `netlify.toml` into the function's `config` (Netlify accepts both, so nothing changes there yet), and add `run.mjs`:

```ts
const name = process.argv[2];
const mod = await import(new URL(`./netlify/functions/${name}.mjs`, import.meta.url));
const req = new Request("http://localhost/", { method: "POST", body: JSON.stringify({ next_run: null }) });
await (mod.default.fetch ?? mod.default)(req, {});
```

Then deploy the job from the service's image and schedule it:

```shell
IMAGE=$(gcloud run services describe shop-api --region europe-west1 \
  --format='value(spec.template.spec.containers[0].image)')
gcloud run jobs deploy nightly --image "$IMAGE" --region europe-west1 \
  --command=node --args=run.mjs,nightly
gcloud scheduler jobs create http nightly --location europe-west1 \
  --schedule="0 5 * * *" --time-zone=Etc/UTC --http-method POST \
  --uri="https://run.googleapis.com/v2/projects/PROJECT_ID/locations/europe-west1/jobs/nightly:run" \
  --oauth-service-account-email=PROJECT_NUMBER-compute@developer.gserviceaccount.com
```

A job is not reachable over HTTP, so nobody on the internet can trigger it, and it is not held to 30 seconds. Keep the time zone in UTC to match Netlify, or set your own; the [cron and timers guide](https://exodus.elim.io/blog/cron-and-timers-with-cloud-scheduler) covers the price, retries and what happens when two runs overlap.

A background function answers 202 at once and keeps working for up to 15 minutes, with two retries. On Google the closest piece is Cloud Tasks: your function adds a task to a queue, and Cloud Tasks calls a route on your service with retries and an OIDC token, for up to 30 minutes. Because the service is public, the route must verify the token. The [background workers guide](https://exodus.elim.io/blog/background-workers-with-cloud-tasks) has the code for both sides, the prices and the retry settings; work longer than 30 minutes goes to a job.

![A table of limits on Netlify and on Google Cloud: request length, background work, scheduled work, request body, memory, region, previews and cookies](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-113e6f7ebe3d4798576a636a9ea32928ebea3814db45ea2dbbac2b1ea1b0b5c5-680x528-svg/bytes "The limits that change in a move, from Netlify's and Google's pages of October 11, 2026")

## Step 6: forms and Identity

Netlify Forms works by detecting `data-netlify="true"` in your HTML at build time and accepting the POST itself. Nothing on Google does that. Add a function, say `netlify/functions/contact.mjs` with `config.path` set to `/api/contact`, that validates the fields, stores them in your database and sends the notification email, and point the form's `action` at it. Before you switch, export the old submissions: `netlify api listSiteSubmissions --data '{"site_id": "SITE_ID"}'` returns them as JSON.

Netlify Identity was deprecated in February 2025 and then kept: Netlify's page now says it remains supported. It is tied to the Netlify site, though, so it cannot follow the domain. Firebase Authentication with Identity Platform covers email, social and anonymous sign-in at no cost up to 50,000 monthly active users. Users will need to sign in again or reset their passwords unless Netlify support exports the accounts for you.

## Step 7: previews

Netlify builds a Deploy Preview for every pull request at `deploy-preview-42--mysitename.netlify.app`, free. Firebase Hosting has preview channels:

```shell
firebase hosting:channel:deploy pr-42 --expires 7d
```

A channel lives 7 days by default and 30 at most. Firebase's GitHub Action creates one for each pull request and comments the URL. The catch is that a preview channel shares the project's real backend: the `/api` rewrite reaches the production Cloud Run service. Add `"pinTag": true` to the `run` block so that each Hosting version is pinned to the service revision deployed with it, and for anything that writes data, keep a second project as staging.

## Step 8: the domain and the switch

Firebase Hosting gives the domain a certificate at no charge. Its Quick Setup asks you to point the domain's A records at Firebase and then mints the certificate, which can take hours; during that time HTTPS fails. A site already in production should use Advanced Setup, which first proves you own the domain by a TXT record (an ACME challenge, the check certificate authorities use), so the certificate exists before traffic moves. [Custom domains and HTTPS on Cloud Run](https://exodus.elim.io/blog/custom-domains-and-https-on-cloud-run) compares Firebase Hosting with a load balancer and domain mapping.

1. A day before, lower the TTL of the records you will change to 300 seconds. If the domain uses Netlify DNS, move the zone to another DNS provider first, as its own step.
1. Deploy the service, the job and Hosting, and test on `PROJECT_ID.web.app`: every redirect, a form, a function, a manual run of the job (`gcloud run jobs execute nightly --region europe-west1 --wait`).
1. Connect the domain with Advanced Setup and wait until the certificate is active.
1. Change the A records to Firebase's and remove the old ones pointing at Netlify (`75.2.60.5` or the CNAME to `*.netlify.app`). Watch the Cloud Run logs for an hour.
1. Remove the scheduled functions from the Netlify site, or they run twice.
1. Keep the Netlify site for a week as the way back, then delete it.

## What breaks most often

- A rule that depended on Netlify's no-shadowing default behaves differently after translation.
- A function reads a cookie that Firebase Hosting stripped, and every user looks signed out.
- A secret came back masked from `env:list`, and the function fails on its first call.
- A request through Hosting runs longer than 60 seconds and returns 504.
- The certificate is still minting when DNS changes, because Quick Setup was used on a live site.
- A preview channel writes to production through the `/api` rewrite.
- Forms post to a path nothing handles any more.

Each of these shows up in the test of step 2 of the switch. The [patterns that break on Cloud Run](https://exodus.elim.io/blog/patterns-that-break-on-cloud-run) guide covers the rest.

## Where Exodus comes in

Exodus's CLI reads `netlify.toml`, `_redirects`, `_headers` and `netlify/functions` on your machine, with your coding agent reading the code for the ambiguous parts. The report lists each piece from the map above with what it becomes: rules that translate to `firebase.json` and the ones that do not, scheduled and background functions with their schedules, forms found in the HTML, functions that read `context` fields or cookies, and the variables the code reads. It then estimates the month on Google for your traffic next to your Netlify credits, and says plainly when staying costs less.

## FAQ

### Is Firebase Hosting cheaper than Netlify?

For a small site, usually: in our model $3 a month against $14 on Netlify, where 40 production deploys use 600 of 1,277 credits. At large traffic the two cost about the same, because bandwidth dominates and both price it near $0.13 to $0.15 per GB.

### Can Netlify functions run on Cloud Run without changes?

Yes. A modern Netlify function takes a web Request and returns a Response, which Node.js has built in, so a small adapter can load every file in netlify/functions and route to it inside one container. Functions that read context.geo, context.ip or context.cookies need those replaced with request headers.

### Does Firebase Hosting support Netlify's _redirects file?

No, the rules move into firebase.json. Splats become captures, a status of 200 becomes a rewrite, and the single-page fallback becomes a rewrite to index.html. Conditions on country, language, role or cookie, and proxies to other sites, have no field there and move into the Cloud Run service.

### Why are users signed out after moving to Firebase Hosting?

Firebase Hosting strips every cookie except one named __session before the request reaches Cloud Run. A function that reads a session cookie by another name sees none, so every user looks signed out. Rename the cookie to __session.

### What replaces Netlify scheduled functions on Google Cloud?

A Cloud Run job, built from the same image with a different command and started by Cloud Scheduler. Unlike a scheduled function it is not held to 30 seconds and is not reachable over HTTP. Keep the time zone in UTC to match Netlify, and remove the old schedule so it does not run twice.

## Sources

1. [Netlify pricing (Free 300 credits, Personal $9 with 1,000, Pro $20 with 3,000 and unlimited members; credit packs $5 per 500 on Personal and $10 per 1,500 on Pro; production deploy 15 credits, compute 10 per GB-hour, bandwidth 20 per GB, web requests 2 per 10,000; read Oct 11, 2026)](https://www.netlify.com/pricing/)
2. [How credits work, Netlify (accounts created before September 4, 2025 keep Legacy plans; Deploy Previews and branch deploys cost 0 credits; what counts as a web request; read Oct 11, 2026)](https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/how-credits-work/)
3. [Credit-based pricing plans, Netlify (Pro tiers 3,000 for $20, 5,000 for $33, 10,000 for $63, 15,000 for $95, 20,000 for $126; form submissions free; read Oct 11, 2026)](https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/credit-based-pricing-plans/)
4. [Personal vs Free, Netlify (on Free, projects pause when the 300 credits run out; Personal is for individual developers; read Oct 11, 2026)](https://www.netlify.com/pricing/personal-vs-free/)
5. [Legacy pricing plans, Netlify (Legacy Pro $19 per member, 1 TB of bandwidth, then $55 per 100 GB; read Oct 11, 2026)](https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-legacy-plans/legacy-pricing-plans/)
6. [Functions configuration, Netlify (region cmh, US East, by default; 1,024 MB; 60 s synchronous, 30 s scheduled, 15 min background; 6 MB buffered payload, about 4.5 MB for binary uploads; /.netlify/functions/NAME and config.path routing; read Oct 11, 2026)](https://docs.netlify.com/build/functions/configuration/)
7. [Functions API, Netlify (a default export receives a web Request and a Context and returns a Response; config.path, config.schedule; read Oct 11, 2026)](https://docs.netlify.com/build/functions/api/)
8. [Scheduled Functions, Netlify (cron in UTC, inline config or netlify.toml, 30 second limit, only on published deploys; read Oct 11, 2026)](https://docs.netlify.com/build/functions/scheduled-functions/)
9. [Background Functions, Netlify (an immediate 202, up to 15 minutes, retried after one and two minutes; config.background or a -background suffix; read Oct 11, 2026)](https://docs.netlify.com/build/functions/background-functions/)
10. [Edge Functions limits, Netlify (Deno runtime, 50 ms of CPU per request, 512 MB; read Oct 11, 2026)](https://docs.netlify.com/build/edge-functions/limits/)
11. [Redirects and rewrites, Netlify (_redirects in the publish directory, processed before netlify.toml, first match wins; status 200 makes a rewrite; read Oct 11, 2026)](https://docs.netlify.com/manage/routing/redirects/overview/)
12. [Redirect options, Netlify (splats, forcing with !, country, language and cookie conditions; read Oct 11, 2026)](https://docs.netlify.com/manage/routing/redirects/redirect-options/)
13. [Rewrites and proxies, Netlify (no shadowing of existing files by default; proxy to another service with status 200; signed proxy redirects; read Oct 11, 2026)](https://docs.netlify.com/manage/routing/redirects/rewrites-proxies/)
14. [Custom headers, Netlify (_headers file; not applied to function or proxied responses; read Oct 11, 2026)](https://docs.netlify.com/manage/routing/headers/)
15. [Forms setup and submissions, Netlify (data-netlify attribute detected at build; 8 MB request and 30 s limit for uploads; submissions through the API; read Oct 11, 2026)](https://docs.netlify.com/manage/forms/setup/)
16. [Netlify + Auth0: Platform extensibility and Identity changes, Netlify (Identity remains supported, updated after the February 2025 deprecation; read Oct 11, 2026)](https://www.netlify.com/blog/auth0-extension-identity-changes/)
17. [Deprecation of Netlify Identity, Netlify changelog (February 28, 2025; Support helps export data to migrate; read Oct 11, 2026)](https://www.netlify.com/changelog/deprecation-netlify-identity/)
18. [Environment variables, Netlify (env:list --plain --context production; deploy contexts and scopes; read Oct 11, 2026)](https://docs.netlify.com/build/environment-variables/get-started/)
19. [Secrets Controller, Netlify (secret values are write-only and masked outside the dev context; read Oct 11, 2026)](https://docs.netlify.com/build/environment-variables/secrets-controller/)
20. [Deploy Previews, Netlify (deploy-preview-42--mysitename.netlify.app; read Oct 11, 2026)](https://docs.netlify.com/deploy/deploy-types/deploy-previews/)
21. [Configure external DNS, Netlify (apex A record to the load balancer 75.2.60.5, subdomains as a CNAME to the netlify.app name; read Oct 11, 2026)](https://docs.netlify.com/manage/domains/configure-domains/configure-external-dns/)
22. [Firebase pricing and Hosting quotas (10 GB of storage and 10 GB a month of transfer at no cost, then $0.026 per GB and $0.15 per GB on Blaze; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/usage-quotas-pricing)
23. [Firebase Hosting product page (custom domain, global CDN and SSL certificate included; read Oct 11, 2026)](https://firebase.google.com/products/hosting)
24. [Firebase Hosting with Cloud Run (rewrite with serviceId and region, a 60 second request timeout, pinTag; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/cloud-run)
25. [Configure Hosting behavior, Firebase (priority order: redirects, exact static files, rewrites; globs and captures; cleanUrls, trailingSlash, headers; rewrite destinations are files, functions or Cloud Run; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/full-config)
26. [Manage cache behavior, Firebase Hosting (dynamic responses are private by default; only the __session cookie reaches Cloud Run; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/manage-cache)
27. [Manage live and preview channels, Firebase Hosting (preview channels expire after 7 days by default, at most 30; rollback; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/manage-hosting-resources)
28. [Deploy to preview channels via GitHub pull requests, Firebase (a GitHub Action comments the preview URL; previews use the project's real backend; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/github-integration)
29. [Connect a custom domain, Firebase Hosting (Quick Setup; Advanced Setup with an ACME challenge for a zero-downtime move; certificates within hours, up to 24; read Oct 11, 2026)](https://firebase.google.com/docs/hosting/custom-domain)
30. [Identity Platform pricing, Google (50,000 monthly active users at no cost, then $0.0055 down to $0.0025 per user; read Oct 11, 2026)](https://cloud.google.com/identity-platform/pricing)
31. [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)
32. [Cloud Run quotas and limits (60 minute request timeout; 32 MiB HTTP/1 request size; read Oct 11, 2026)](https://docs.cloud.google.com/run/quotas)
33. [Allowing public access, Cloud Run (--allow-unauthenticated or the invoker check disabled; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/authenticating/public)
34. [Execute jobs on a schedule, Cloud Run (Cloud Scheduler POST to the jobs/JOB:run URI with an OAuth token; read Oct 11, 2026)](https://docs.cloud.google.com/run/docs/execute/jobs-on-schedule)
35. [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)
36. [Cloud Tasks pricing, Google (1 million operations a month free, then $0.40 per million; read Oct 11, 2026)](https://cloud.google.com/tasks/pricing)
37. [Cloud Tasks Task reference (HTTP task dispatch deadline 10 minutes by default, 15 seconds to 30 minutes; OIDC token; read Oct 11, 2026)](https://docs.cloud.google.com/tasks/docs/reference/rest/v2/projects.locations.queues.tasks)
38. [Cloud CDN pricing, Google (cache egress to Europe $0.08 per GiB under 10 TiB; cache fill $0.01 per GiB; $0.0075 per 10,000 lookups; read Oct 11, 2026)](https://cloud.google.com/cdn/pricing)
39. Exodus team: a sample Netlify project with v1 and v2 functions run through the adapter in this guide with Docker, and its firebase.json in the Firebase Hosting emulator, on Oct 11, 2026; the cost model and its arithmetic
