Cloud Functions vs traditionelles Backend: Wann Serverless sinnvoll ist
Ein praxisnaher Vergleich von Serverless Functions und traditionellen Backends — Kosten, Latenz, Developer Experience und wann welcher Ansatz gewinnt.

Jedes Greenfield-Projekt, das ich starte, erzwingt dieselbe Entscheidung: Starte ich einen traditionellen Server oder schreibe ich Cloud Functions? Nachdem ich Produktionssysteme auf beiden Seiten ausgeliefert habe — Firebase Functions für Event-getriebene Workflows, AWS Lambda für API-Endpunkte und Express/Fastify-Server für alles dazwischen — habe ich eine ziemlich differenzierte Meinung darüber, wann welcher Ansatz wirklich gewinnt. Die Antwort ist vorhersagbar „es kommt darauf an", aber die Einzelheiten, worauf es ankommt, sind es wert, im Detail untersucht zu werden.
Die beiden Ansätze definieren
Bevor wir vergleichen, möchte ich präzisieren, was ich mit jedem meine.
Traditionelles Backend bezeichnet einen langlebigen Serverprozess — eine Node.js Express-App, einen Python FastAPI-Server, einen Go HTTP-Server — deployt auf einer VM, einem Container oder einer Managed-Compute-Plattform. Der Prozess startet, bleibt laufend und bearbeitet Anfragen, wenn sie eintreffen. Deployment-Ziele sind EC2, Cloud Run, ECS, Railway, Fly.io oder ein einfacher VPS.
Cloud Functions (Serverless Functions) sind einzelne Funktions-Handler, die als Reaktion auf Events ausgeführt werden. Die Plattform verwaltet die Compute-Infrastruktur vollständig. Ihr Code wird ausgeführt, gibt eine Antwort zurück, und die Ausführungsumgebung bleibt möglicherweise bestehen oder auch nicht für den nächsten Aufruf. Anbieter sind AWS Lambda, Google Cloud Functions, Firebase Functions, Azure Functions und Cloudflare Workers.
Der Unterschied liegt nicht in der Sprache oder dem Framework — sondern im Ausführungsmodell. Ein traditionelles Backend besitzt seinen Prozesslebenszyklus. Eine Cloud Function nicht.
Die Cold-Start-Realität
Cold Starts sind die meistdiskutierte Serverless-Einschränkung, und die Realität in 2026 ist differenzierter als der Diskurs vermuten lässt.
Was bei einem Cold Start tatsächlich passiert
Wenn eine Cloud Function kürzlich nicht aufgerufen wurde (oder wenn gleichzeitige Aufrufe die verfügbaren warmen Instanzen übersteigen), muss die Plattform:
- Eine neue Ausführungsumgebung provisionieren (MicroVM oder Container)
- Ihr Deployment-Paket herunterladen und entpacken
- Die Runtime initialisieren (Node.js, Python, etc.)
- Ihren Initialisierungscode ausführen (Modul-Imports, SDK-Setup, DB-Verbindungen)
- Den eigentlichen Funktions-Handler ausführen
Schritte 1-3 sind Plattform-Overhead. Schritt 4 ist, wo Ihre Code-Entscheidungen enorm zählen.
Cold-Start-Zeiten in der Praxis
Hier sind die Cold-Start-Zeiten, die ich über verschiedene Plattformen und Konfigurationen in echten Projekten gemessen habe:
| Plattform | Runtime | Bundle-Größe | Cold Start |
|---|---|---|---|
| AWS Lambda | Node.js 20 | 5 MB | 250-400 ms |
| AWS Lambda | Node.js 20 | 50 MB | 800-1200 ms |
| AWS Lambda | Python 3.12 | 10 MB | 400-600 ms |
| Firebase Functions v2 | Node.js 20 | 15 MB | 600-1000 ms |
| Cloudflare Workers | JavaScript | 1 MB | 0-5 ms |
| Google Cloud Functions v2 | Node.js 20 | 10 MB | 300-500 ms |
Cloudflare Workers sind der Ausreißer, weil sie V8 Isolates statt Container verwenden, was die Container-Startstrafe vollständig eliminiert. Der Kompromiss ist eine eingeschränktere Laufzeitumgebung.
Cold Starts reduzieren
Es gibt mehrere Strategien, die wirklich helfen:
Provisioned Concurrency (Lambda): Hält N Instanzen dauerhaft warm. Kostet 0,0000041667 $ pro GB-Sekunde provisionierter Kapazität. Für eine 256-MB-Funktion sind das etwa 3,20 $/Monat pro warme Instanz. Lohnt sich für latenzsensitive Endpunkte.
Minimum Instances (Cloud Run, Firebase Functions v2): Gleiches Konzept, andere Bezeichnung. Cloud Run berechnet untätige Instanzen zu einem reduzierten Tarif.
Bundle-Größe reduzieren: Das hat das beste Aufwand-Wirkung-Verhältnis. Tree-Shaking, Ausschluss von Dev-Dependencies und die Verwendung leichterer SDK-Clients reduzieren die Initialisierungszeit dramatisch.
// Bad: imports the entire AWS SDK (adds 40MB+ to bundle)
import AWS from 'aws-sdk';
// Good: imports only the S3 client (adds ~3MB)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
Lazy Initialization: Stellen Sie Datenbankverbindungen nicht auf Modulebene her und laden Sie keine schweren Ressourcen. Initialisieren Sie sie beim ersten Aufruf und verwenden Sie sie über warme Aufrufe hinweg wieder.
import { Pool } from 'pg';
let pool: Pool | null = null;
function getPool(): Pool {
if (!pool) {
pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 1, // Single connection per Lambda instance
});
}
return pool;
}
export async function handler(event: APIGatewayEvent) {
const db = getPool();
const result = await db.query('SELECT * FROM users WHERE id = $1', [event.pathParameters?.id]);
return { statusCode: 200, body: JSON.stringify(result.rows[0]) };
}
Kostenvergleich bei verschiedenen Skalierungen
Kosten sind der Punkt, an dem die Diskussion interessant wird, denn die Wirtschaftlichkeit kehrt sich mit zunehmender Skalierung um.
Geringer Traffic (1.000 - 50.000 Anfragen/Tag)
Bei dieser Skalierung ist Serverless fast immer günstiger. Viele Startups und Nebenprojekte fallen hierein.
Lambda-Kosten für 30.000 Anfragen/Tag, 200 ms durchschnittliche Dauer, 256 MB Speicher:
- Anfrage-Gebühren: 900K Anfragen/Monat x 0,20 $/Million = 0,18 $
- Compute-Gebühren: 900K x 0,2s x 0,25GB x 0,0000166667 $ = 0,75 $
- Gesamt: ~1 $/Monat
Äquivalenter traditioneller Server (t4g.small auf AWS):
- On-Demand: 12,26 $/Monat
- Mit 1-Jahres-Savings-Plan: ~8 $/Monat
Bei geringem Traffic bezahlen Sie für einen Always-On-Server, der zu 95 % untätig ist.
Mittlerer Traffic (100.000 - 1.000.000 Anfragen/Tag)
Dies ist die Übergangszone, in der der Vergleich knapp wird.
Lambda-Kosten für 500.000 Anfragen/Tag, 200 ms Durchschnitt, 256 MB:
- Anfrage-Gebühren: 15M/Monat x 0,20 $/Million = 3,00 $
- Compute-Gebühren: 15M x 0,2s x 0,25GB x 0,0000166667 $ = 12,50 $
- Gesamt: ~15,50 $/Monat
t4g.medium (2 vCPU, 4 GB RAM):
- On-Demand: 24,53 $/Monat
- Mit Savings Plan: ~16 $/Monat
Die Kosten sind vergleichbar, aber der traditionelle Server bewältigt diesen Traffic mit erheblicher Reserve. Wenn Ihr Traffic gleichmäßig ist, ist der Server etwas günstiger. Wenn Ihr Traffic schwankend ist (werktags-lastig, Event-getriebene Spitzen), bedeutet Lambdas Abrechnung pro Aufruf, dass Sie für ruhige Zeiten nicht bezahlen.
Hoher Traffic (5.000.000+ Anfragen/Tag)
Bei dieser Skalierung ist Serverless für anhaltende Workloads fast immer teurer.
Lambda-Kosten für 5.000.000 Anfragen/Tag, 200 ms Durchschnitt, 512 MB:
- Anfrage-Gebühren: 150M/Monat x 0,20 $/Million = 30 $
- Compute-Gebühren: 150M x 0,2s x 0,5GB x 0,0000166667 $ = 250 $
- Gesamt: ~280 $/Monat
c6g.large (2 vCPU, 4 GB RAM) mit Auto-Scaling-Gruppe:
- 2 Instanzen mit Savings Plan: ~60 $/Monat
- Mit Load Balancer: ~16 $/Monat
- Gesamt: ~76 $/Monat
Der traditionelle Ansatz ist bei dieser Skalierung 3,7x günstiger, und die Lücke weitet sich mit zunehmendem Traffic.
Versteckte Kosten beachten
Lambdas Abrechnung ist nicht das vollständige Bild. Addieren Sie API Gateway (1-3,50 $ pro Million Anfragen), CloudWatch Logs (0,50 $/GB aufgenommen) und X-Ray Tracing, falls verwendet. Auf der traditionellen Seite addieren Sie Load-Balancer-Kosten, Monitoring und die Ops-Zeit für die Verwaltung von Instanzen und Deployments.
Unterschiede in der Developer Experience
Serverless DX
Vorteile:
- Keine Infrastruktur zu verwalten (kein Patching, keine Skalierungskonfiguration)
- Deployment pro Funktion bedeutet kleineren Blast Radius
- Lokale Entwicklung mit Emulatoren (Firebase Emulator Suite, SAM CLI, Serverless Framework offline)
- Eingebaute Observability über Logging und Tracing der Plattform
Schmerzpunkte:
- Lokale Entwicklung stimmt nie perfekt mit dem Produktionsverhalten überein
- Debugging verteilter Function-to-Function-Aufrufe ist schwieriger als Stepping durch einen Monolithen
- Deployment-Größenlimits (Lambda: 250 MB entpackt) schränken die Abhängigkeitswahl ein
- IAM- und Berechtigungskonfiguration ist ausführlich und leicht falsch zu machen
- Cold Starts verlangsamen Entwicklungsiterationsschleifen beim Testen gegen deployte Funktionen
Traditionelle Backend DX
Vorteile:
- Die lokale Entwicklungsumgebung ist die Produktionsumgebung (gleicher Prozess, gleicher State)
- Debugging ist unkompliziert — Debugger anhängen, Breakpoints setzen, durchsteppen
- Keine Deployment-Größenlimits
- Middleware-Patterns, Request-Lifecycle-Hooks und globale Fehlerbehandlung sind natürlich
- WebSocket-Unterstützung, langlebige Prozesse und Hintergrundjobs funktionieren ohne zusätzliche Services
Schmerzpunkte:
- Sie sind verantwortlich für den Infrastruktur-Lebenszyklus (Updates, Skalierung, Health Checks)
- Deployments erfordern Orchestrierung (Rolling Updates, Health-Check-Wartezeiten)
- Skalierung erfordert Konfiguration (Auto-Scaling-Gruppen, Container-Orchestrierung)
- Monitoring und Logging erfordern explizites Setup
Die Framework-Lücke schließt sich
Frameworks wie SST (Serverless Stack) und Architect haben die Serverless DX dramatisch verbessert. SST bietet insbesondere einen „Live Lambda"-Entwicklungsmodus, bei dem Ihr lokal laufender Code Lambda-Aufrufe in Echtzeit bearbeitet, was den Deploy-Test-Zyklus vollständig eliminiert.
Auf der traditionellen Seite haben Plattformen wie Railway, Fly.io und Render das Deployment zu einem git push vereinfacht. Der Ops-Aufwand für den Betrieb eines traditionellen Backends hat sich deutlich verringert.
Wann Serverless gewinnt
Event-getriebene Workloads
Wenn Ihr Code als Reaktion auf Events läuft — Datei-Uploads, Datenbankänderungen, Queue-Nachrichten, geplante Aufgaben — ist Serverless die natürliche Wahl. Sie unterhalten keine Polling-Schleife oder einen Listener-Prozess. Die Plattform triggert Ihren Code genau wenn nötig.
// Firebase Functions: triggered on Firestore document creation
import { onDocumentCreated } from 'firebase-functions/v2/firestore';
export const onOrderCreated = onDocumentCreated('orders/{orderId}', async (event) => {
const order = event.data?.data();
if (!order) return;
// Send confirmation email
await sendEmail(order.customerEmail, {
template: 'order-confirmation',
data: { orderId: event.params.orderId, items: order.items },
});
// Update inventory
await updateInventory(order.items);
// Notify restaurant
await sendPushNotification(order.restaurantId, {
title: 'New Order',
body: `Order #${event.params.orderId} received`,
});
});
Sporadischer oder unvorhersehbarer Traffic
Ein internes Tool, das am Montagmorgen 50 Anfragen und den Rest der Woche 2 Anfragen bekommt. Ein Webhook-Empfänger, der Events von einer Drittanbieter-API verarbeitet. Ein geplanter Berichtsgenerator, der einmal am Tag 30 Sekunden läuft. Diese Workloads haben auf Serverless fast keine Kosten und verschwenden auf Always-On-Infrastruktur Geld.
API-Endpunkte mit geringem bis mittlerem Traffic
Für die MVP-API eines Startups, die ein paar tausend Anfragen pro Tag bedient, bietet Serverless ein funktionales Backend mit minimalem Ops-Overhead und fast keinen Kosten. Sie können sich vollständig auf die Geschäftslogik konzentrieren.
Parallele Datenverarbeitung
Müssen Sie 10.000 Bilder verarbeiten, 500 Videos transkodieren oder Analytics auf einem großen Datensatz ausführen? Fächern Sie auf Tausende gleichzeitiger Lambda-Aufrufe auf, verarbeiten Sie parallel und zahlen Sie nur für die genutzte Rechenzeit. Dieselbe Parallelität mit traditionellen Servern zu erreichen, erfordert die Provisionierung (und Bezahlung) dieser Spitzenkapazität.
Wann traditionelle Backends gewinnen
Persistente Verbindungen
WebSocket-Verbindungen, Server-Sent Events, gRPC-Streams und Long-Polling erfordern alle eine persistente Verbindung zwischen Client und Server. Lambda-Funktionen haben ein 15-Minuten-Ausführungslimit und sind nicht für langlebige Verbindungen konzipiert.
Sie können das mit API Gateway WebSocket APIs oder AWS IoT Core umgehen, aber die Komplexität und Kosten übersteigen oft einen einfachen WebSocket-Server auf Cloud Run oder einer Container-Plattform.
Komplexe Request-Pipelines
Wenn eine Anfrage durch Authentifizierung, Rate Limiting, Input-Validierung, Geschäftslogik, Datenbankoperationen, Cache-Updates, Event-Emission und Antwortformatierung läuft — ist das Middleware-Pipeline-Pattern von Express/Fastify/Koa ergonomisch überlegen gegenüber dem flachen Handler-Pattern von Cloud Functions.
// Traditional: clean middleware pipeline
app.use(cors());
app.use(helmet());
app.use(rateLimiter);
app.use(authenticate);
app.use('/api/v1', apiRouter);
app.use(errorHandler);
Dies in Lambda zu replizieren erfordert entweder ein Framework wie Middy (das Gewicht und Komplexität hinzufügt) oder dupliziertem Setup-Code über Funktionen hinweg.
Stateful-Operationen
Wenn Ihre Anwendung In-Memory-State pflegt — einen Cache, einen Connection Pool, einen Rate-Limiter-Counter, Session-Daten — handhabt ein traditioneller Server das natürlich. Lambda-Funktionen können State über warme Aufrufe hinweg wiederverwenden, aber Sie können sich nicht darauf verlassen. Jeder State, der persistieren muss, braucht einen externen Service (Redis, DynamoDB), was Latenz und Kosten hinzufügt.
Strikte Latenzanforderungen
Für APIs, bei denen jede Millisekunde zählt — Real-Time-Bidding, Game-Server, Finanztransaktionen — ist die unvorhersehbare Latenz durch Cold Starts inakzeptabel, selbst mit Provisioned Concurrency. Ein gut abgestimmter Serverprozess mit Connection Pooling und warmen Caches liefert konsistente Sub-10-ms-Antwortzeiten, die Serverless nicht garantieren kann.
Der hybride Ansatz
In der Praxis sind die meisten Produktionssysteme, die ich baue, hybrid. Die Kern-API läuft auf einem traditionellen Backend (Cloud Run oder eine Container-Plattform), während Nebenaufgaben auf Cloud Functions laufen.
Eine praktische hybride Architektur
Client
│
├─→ API Gateway / Load Balancer
│ └─→ Cloud Run (main API)
│ ├─→ PostgreSQL (Cloud SQL)
│ ├─→ Redis (Memorystore)
│ └─→ Pub/Sub (event bus)
│
└─→ Cloud Functions (event handlers)
├─→ Image processing (on upload)
├─→ Email sending (on order creation)
├─→ Analytics aggregation (scheduled)
└─→ Webhook processing (HTTP trigger)
Die Haupt-API bearbeitet synchronen Request-Response-Traffic mit persistenten Datenbankverbindungen, In-Memory-Caching und konsistenter Latenz. Cloud Functions bearbeiten asynchrone, Event-getriebene Workloads, bei denen Cold Starts keine Rolle spielen, weil der Nutzer nicht auf eine Antwort wartet.
Migrationsstrategie: Traditionell zu Serverless
Wenn Sie ein bestehendes traditionelles Backend haben und Serverless selektiv einführen möchten:
- Event-getriebene Operationen identifizieren, die derzeit als Hintergrundjobs, Cron-Aufgaben oder Queue-Consumer laufen. Diese sind am einfachsten zu migrieren.
- Unabhängige Endpunkte extrahieren, die keinen State mit anderen Endpunkten teilen. Health-Check-Endpunkte, Webhook-Empfänger und Utility-APIs sind gute Kandidaten.
- Die Kern-API traditionell belassen, es sei denn, es gibt einen zwingenden Grund, sie zu zerlegen. Der operative Overhead der Verwaltung von 50 Lambda-Funktionen übersteigt oft den einer einzigen Container-Verwaltung.
- Einen Event-Bus verwenden (Pub/Sub, EventBridge, SQS) als Integrationsschicht zwischen Ihrer traditionellen API und Serverless Functions. Die API veröffentlicht Events; Funktionen abonnieren und reagieren.
Migrationsstrategie: Serverless zu Traditionell
In die andere Richtung zu gehen ist manchmal notwendig, wenn eine Serverless-API ihre Architektur überwächst:
- Nicht alles auf einmal umschreiben. Beginnen Sie damit, die Funktionen mit dem meisten Traffic in einen einzelnen API-Server zu konsolidieren.
- Event-getriebene Funktionen als Funktionen belassen. Nur Request-Response-Handler migrieren.
- Dieselben API-Routen verwenden. Ihren API Gateway/Load Balancer für migrierte Routen auf den neuen Server zeigen lassen und weiterhin für den Rest an Lambda routen.
- Datenbankverbindungen zuerst migrieren. Der größte Performance-Gewinn ist der Wechsel von Pro-Aufruf-Verbindungsaufbau zu persistentem Connection Pooling.
Plattformspezifische Hinweise
Firebase Functions (v2)
Firebase Functions v2 läuft im Hintergrund auf Cloud Run, was erhebliche Vorteile gegenüber v1 bietet: konfigurierbare Concurrency (mehrere Anfragen pro Instanz), Minimum Instances, längere Timeouts (bis zu 60 Minuten) und größere Speicherzuweisungen. Wenn Sie noch auf Firebase v1 Functions sind, lohnt sich das Upgrade auf v2.
Die Firebase Emulator Suite bietet die beste lokale Entwicklungserfahrung im Serverless-Bereich. Sie emuliert Firestore, Auth, Storage und Functions in einer einzigen lokalen Umgebung mit Hot-Reload bei Codeänderungen.
AWS Lambda
Lambda hat das tiefste Integrationsökosystem — Trigger von praktisch jedem AWS-Service, Layers für geteilten Code und SnapStart für Java-Workloads. Das Function-URL-Feature eliminiert die Notwendigkeit von API Gateway für einfache Anwendungsfälle und spart 3,50 $ pro Million Anfragen.
Lambda@Edge und CloudFront Functions sind leistungsstark für Request/Response-Manipulation auf CDN-Ebene, aber die Entwicklungs- und Debugging-Erfahrung ist deutlich schlechter als bei Standard-Lambda.
Cloud Run
Cloud Run verwischt die Grenze zwischen Serverless und Traditionell. Es führt Container aus (jede Sprache, jedes Framework), skaliert auf null und unterstützt Concurrency (mehrere Anfragen pro Instanz). Es ist serverless im Abrechnungsmodell, aber traditionell im Ausführungsmodell. Für Teams, die Serverless-Wirtschaftlichkeit ohne Umschreiben ihres Codes als Funktions-Handler wollen, ist Cloud Run oft die richtige Antwort.
Die Entscheidung treffen
Hier ist das Entscheidungs-Framework, das ich verwende:
- Ist der Workload Event-getrieben und asynchron? Serverless.
- Ist der Traffic gering und unvorhersehbar? Serverless.
- Brauchen Sie persistente Verbindungen oder In-Memory-State? Traditionell.
- Ist konsistent niedrige Latenz kritisch? Traditionell.
- Ist das Team klein und ops-avers? Serverless (oder Cloud Run).
- Ist der Traffic hoch und gleichmäßig? Traditionell (günstiger).
- Ist es eine Mischung aus dem Obigen? Hybrid.
Die schlechteste Entscheidung ist, dies als Alles-oder-Nichts-Wahl zu behandeln. Verwenden Sie das richtige Tool für jeden Workload, verbinden Sie sie über gut definierte Interfaces, und Sie erhalten die Vorteile beider, ohne sich vollständig auf einen festzulegen.
Danil Ulmashev
Full Stack Developer
Interesse an einer Zusammenarbeit?