Stack in JavaScript und TypeScript: LIFO verstehen und umsetzen

Stack in JavaScript und TypeScript: LIFO verstehen und umsetzen

Vom Call Stack bis zur Undo-Funktion: wie die Datenstruktur arbeitet, was ihre Operationen kosten und wie Sie sie sauber implementieren

Aktualisiert:

Abstract

Stack in JavaScript und TypeScript: wie das LIFO-Prinzip funktioniert, wie Sie einen typsicheren Stack bauen und wofür er sich in der Praxis eignet.
  • #Stack
  • #Datenstruktur
  • #JavaScript
  • #TypeScript
  • #Implementierung
  • #Performance
  • #LIFO
  • #Call Stack

Warum ein Stapel oft die einfachste Antwort auf knifflige Probleme ist

Sie drücken in einem Texteditor dreimal Strg+Z, und die letzten drei Änderungen verschwinden, die jüngste zuerst. Hinter diesem Verhalten steckt eine der einfachsten Datenstrukturen der Informatik: der Stack, auf Deutsch Stapel oder Kellerspeicher. Was zuletzt hineingelegt wurde, kommt als Erstes wieder heraus.

Ein Stack kann weniger als ein Array, und gerade das macht ihn nützlich. Wer nur von oben ablegen und entnehmen darf, kann die Reihenfolge nicht versehentlich durcheinanderbringen. Dieser Beitrag zeigt, wie das Prinzip funktioniert, wo JavaScript selbst einen Stack führt, wie Sie einen sauberen Stack in JavaScript und TypeScript schreiben und für welche Aufgaben er sich eignet.

Wie ein Stack funktioniert: das LIFO-Prinzip

Ein Stack arbeitet nach dem Prinzip Last In, First Out, kurz LIFO: Das zuletzt abgelegte Element wird zuerst wieder entnommen. Das bekannte Bild ist der Stapel Tabletts in der Kantine. Gespülte Tabletts kommen oben drauf, wer eines braucht, nimmt das oberste. An ein Tablett in der Mitte kommt niemand heran, ohne vorher die darüberliegenden abzuheben.

Für diese Arbeitsweise haben sich drei Begriffe eingebürgert:

  • push legt ein Element oben auf den Stapel.
  • pop nimmt das oberste Element herunter und gibt es zurück.
  • peek (manchmal auch top) zeigt das oberste Element, ohne es zu entfernen.

Dazu kommen meist Hilfsfunktionen wie isEmpty() und eine Größenangabe. Mehr gehört zum Kern nicht dazu. Das Gegenstück ist die Warteschlange nach dem FIFO-Prinzip (First In, First Out), bei der das älteste Element zuerst an die Reihe kommt. Wie sich Queues und ihre Erweiterung, die Deque, in JavaScript umsetzen lassen, beschreibt der Beitrag zu Queue und Deque in JavaScript.

Der Call Stack: Wo JavaScript selbst einen Stapel führt

Jede JavaScript-Engine verwaltet Funktionsaufrufe auf einem Stack, dem Call Stack (Aufrufstapel). Ruft eine Funktion eine andere auf, legt die Engine einen neuen Eintrag mit deren lokalen Variablen und der Rücksprungadresse oben auf. Ist die aufgerufene Funktion fertig, wird der Eintrag entfernt, und die Ausführung geht beim Aufrufer weiter.

Diesen Stapel sehen Entwickler:innen täglich, ohne darüber nachzudenken. Der Stack Trace in einer Fehlermeldung ist nichts anderes als ein Abbild des Call Stacks im Moment des Fehlers, die zuletzt aufgerufene Funktion steht ganz oben. Und der Fehler RangeError: Maximum call stack size exceeded, so lautet er in Node.js, Chrome und Safari, zeigt, dass der Stapel eine begrenzte Größe hat. Firefox meldet stattdessen InternalError: too much recursion:

function depth(n) {
  return n === 0 ? 0 : 1 + depth(n - 1);
}

try {
  depth(1_000_000);
} catch (error) {
  console.log(error instanceof RangeError); // true (Node.js)
  console.log(error.message); // 'Maximum call stack size exceeded'
}

Wie tief der Stapel werden darf, legt die jeweilige Engine fest, und der Wert hängt unter anderem davon ab, wie viel Platz ein einzelner Aufruf belegt. Wer sehr tiefe Strukturen rekursiv verarbeitet, etwa einen verschachtelten Verzeichnisbaum oder ein großes JSON-Dokument, stößt irgendwann an diese Grenze. Ein selbst verwalteter Stack ist dann der übliche Ausweg, dazu weiter unten mehr.

Ein Stack in modernem JavaScript

Die naheliegende Grundlage ist ein Array. Dessen Methoden push() und pop() arbeiten bereits am Ende des Arrays und verhalten sich damit genau wie ein Stapel. Eine eigene Klasse legt eine schmale Schnittstelle darüber und verhindert, dass jemand über Index-Zugriffe oder splice() mitten in den Stapel greift:

class Stack {
  #items = [];

  push(element) {
    this.#items.push(element);
    return this;
  }

  pop() {
    return this.#items.pop();
  }

  peek() {
    return this.#items.at(-1);
  }

  isEmpty() {
    return this.#items.length === 0;
  }

  get size() {
    return this.#items.length;
  }

  clear() {
    this.#items.length = 0;
  }

  // Von oben nach unten durchlaufen, ohne den Stack zu verändern
  *[Symbol.iterator]() {
    for (let i = this.#items.length - 1; i >= 0; i--) {
      yield this.#items[i];
    }
  }
}

const stack = new Stack();
stack.push('A').push('B').push('C');

console.log(stack.peek()); // 'C'
console.log(stack.pop()); // 'C'
console.log(stack.size); // 2
console.log([...stack]); // [ 'B', 'A' ]

Einige Details lohnen einen zweiten Blick. Das Feld #items ist ein privates Klassenfeld: Das Rautezeichen sorgt dafür, dass Code außerhalb der Klasse nicht darauf zugreifen kann, auch nicht versehentlich. at(-1) liefert das letzte Element eines Arrays und liest sich besser als items[items.length - 1]. Weil push() die Instanz zurückgibt, lassen sich Aufrufe verketten. Der Iterator erlaubt Spread-Syntax und for...of, und zwar in der Reihenfolge, in der ein Stapel gelesen wird: von oben nach unten.

Die Größe ist hier als Getter umgesetzt, also als stack.size ohne Klammern. Das entspricht dem Stil von Map und Set. Eine Methode size() funktioniert ebenso, entscheidend ist, dass ein Projekt sich auf eine Variante festlegt. Wie Arrays intern arbeiten und welche Methoden welchen Zweck erfüllen, vertieft der Beitrag über Best Practices für JavaScript-Arrays.

Ein typsicherer Stack in TypeScript

In TypeScript bekommt der Stack einen Typparameter. Stack<T> legt beim Anlegen fest, welche Art von Elementen auf dem Stapel liegen darf, und der Compiler prüft das bei jedem push():

interface ReadonlyStack<T> {
  peek(): T | undefined;
  isEmpty(): boolean;
  readonly size: number;
}

class Stack<T> implements ReadonlyStack<T> {
  #items: T[] = [];

  push(item: T): this {
    this.#items.push(item);
    return this;
  }

  pop(): T | undefined {
    return this.#items.pop();
  }

  peek(): T | undefined {
    return this.#items.at(-1);
  }

  isEmpty(): boolean {
    return this.#items.length === 0;
  }

  get size(): number {
    return this.#items.length;
  }
}

type EditAction =
  | { kind: 'insert'; position: number; text: string }
  | { kind: 'delete'; position: number; length: number };

const undoHistory = new Stack<EditAction>();
undoHistory.push({ kind: 'insert', position: 0, text: 'Angebot' });
// undoHistory.push('Angebot'); // Fehler: string ist keine EditAction

const last = undoHistory.pop();
if (last?.kind === 'insert') {
  console.log(`Rückgängig: ${last.text.length} Zeichen entfernen`);
}

Zwei Punkte machen den Unterschied zu einem untypisierten Stack. Erstens geben pop() und peek() den Typ T | undefined zurück. TypeScript zwingt damit an jeder Aufrufstelle zur Prüfung, ob überhaupt ein Element da war. Zweitens trennt das Interface ReadonlyStack<T> lesenden von schreibendem Zugriff. Eine Funktion, die nur nachsehen soll, was oben liegt, bekommt den schmaleren Typ und kann den Stapel nicht verändern.

Die Union EditAction zeigt nebenbei ein typisches Muster: Auf dem Stack liegen keine beliebigen Objekte, sondern genau beschriebene Aktionen, die der Compiler anhand des Felds kind unterscheidet. Der Code verzichtet bewusst auf TypeScript-Konstrukte wie enum oder Parameter-Properties im Konstruktor, sodass er sich auch mit dem Type Stripping von Node.js direkt ausführen lässt. Weitere Regeln für typsicheren Code sammelt der Beitrag TypeScript Best Practices: Acht Regeln für typsicheren Code.

Was push und pop kosten

Alle Kernoperationen eines Array-basierten Stacks arbeiten am Ende des Arrays. Dort muss kein anderes Element verschoben werden, deshalb ist der Aufwand unabhängig davon, wie viele Elemente auf dem Stapel liegen. In der O-Notation heißt das O(1), konstante Zeit.

OperationAufwandAnmerkung
push()O(1) im Mittelgelegentlich wächst der interne Speicher
pop()O(1)entfernt das letzte Element
peek()O(1)reiner Lesezugriff
isEmpty(), sizeO(1)liest nur die Länge
Suche im StapelO(n)gehört nicht zum Konzept eines Stacks

Der Zusatz „im Mittel“ bei push() hat einen Grund. Ein Array reserviert intern Speicher mit etwas Reserve. Ist dieser voll, legt die Engine einen größeren Bereich an und kopiert die vorhandenen Elemente hinüber, was einmalig O(n) kostet. Weil der neue Bereich deutlich größer ist, passiert das selten, und verteilt auf alle Aufrufe bleibt der Aufwand konstant. Fachleute sprechen von amortisierter Laufzeit. Was hinter solchen Angaben steckt und wie Sie Laufzeiten selbst einschätzen, erklärt der Beitrag zur Big-O-Notation in der Praxis.

Interessant wird der Vergleich mit einer Warteschlange. Entnimmt man dort mit shift() vorn, muss die Engine in der Regel alle übrigen Elemente nachrücken lassen. Ein Stack hat dieses Problem nicht, weil er nur am Ende arbeitet.

Array oder Objekt mit Zähler?

In vielen Lehrbüchern und älteren Tutorials findet sich eine zweite Variante: ein Objekt als Speicher, dessen Schlüssel 0, 1, 2 … ein eigener Zähler vergibt. Beim Entnehmen löscht delete den obersten Eintrag. Begründet wird das meist mit besserer Performance, weil keine Array-Reallokation nötig sei.

Für aktuelle JavaScript-Engines trägt dieses Argument nicht weit. Auch Objekte brauchen Speicher, der mitwachsen muss, und Engines legen ganzzahlige Schlüssel ähnlich ab wie Array-Elemente. Häufiges delete kann eine Engine sogar dazu bringen, auf eine langsamere interne Darstellung umzuschalten. Dazu kommt, dass ein Objekt keine Methoden wie at(), map() oder join() mitbringt, die beim Debuggen und Ausgeben helfen.

Unsere Empfehlung: Nehmen Sie das Array. Es ist für genau dieses Zugriffsmuster gebaut, jedem im Team vertraut und in allen Engines stark optimiert. Wer dennoch Zweifel hat, sollte mit realistischen Datenmengen in der Zielumgebung messen, statt sich auf allgemeine Aussagen zu verlassen, diese eingeschlossen. Eine verkettete Liste ist eine weitere Möglichkeit, einen Stack zu bauen. Sie lohnt sich in JavaScript selten, wie der Beitrag über verkettete Listen in JavaScript begründet.

Leerer Stack und undefined: Fehler bewusst behandeln

Was soll passieren, wenn jemand pop() auf einem leeren Stack aufruft? Das Array gibt in diesem Fall undefined zurück, und die Klasse oben übernimmt dieses Verhalten. Das ist bequem, hat aber einen Haken: Liegt undefined als echter Wert auf dem Stapel, lässt sich nicht mehr unterscheiden, ob der Stapel leer war oder ob gerade dieser Wert entnommen wurde.

Ältere Implementierungen lösen das, indem sie undefined beim Ablegen verbieten. Sauberer ist es, den leeren Zustand selbst als Fehler zu behandeln. Fachlich heißt dieser Zustand Stack Underflow:

class StackUnderflowError extends Error {
  constructor() {
    super('Der Stack ist leer');
    this.name = 'StackUnderflowError';
  }
}

class StrictStack {
  #items = [];

  push(element) {
    this.#items.push(element);
  }

  pop() {
    if (this.#items.length === 0) {
      throw new StackUnderflowError();
    }
    return this.#items.pop();
  }

  peek() {
    if (this.#items.length === 0) {
      throw new StackUnderflowError();
    }
    return this.#items.at(-1);
  }

  get size() {
    return this.#items.length;
  }

  toString() {
    const entries = this.#items.map((item) => JSON.stringify(item));
    return `Stack(${this.#items.length}) [${entries.join(', ')}]`;
  }
}

const strict = new StrictStack();
strict.push(undefined);
console.log(strict.pop()); // undefined – ein echter Wert, kein Fehler

try {
  strict.pop();
} catch (error) {
  console.log(error.name); // 'StackUnderflowError'
}

Welche Variante passt, hängt vom Einsatz ab. Für Hilfsfunktionen innerhalb eines Moduls genügt meist die tolerante Version mit undefined, kombiniert mit einer Prüfung über isEmpty(). Für eine Klasse, die in mehreren Teilen einer Anwendung verwendet wird, ist der explizite Fehler die robustere Wahl. Er fällt im Test sofort auf, statt als undefined unbemerkt weiterzuwandern. Die Methode toString() hilft beim Debuggen, weil Logausgaben den Inhalt in lesbarer Form zeigen.

Wofür sich ein Stack in der Praxis eignet

Immer wenn ein Programm „zurück zum zuletzt Begonnenen“ muss, ist ein Stack die natürliche Struktur. Vier Beispiele zeigen die Bandbreite.

Rückgängig und Wiederholen mit zwei Stacks

Eine Undo-Funktion braucht einen Stapel mit früheren Zuständen. Soll auch Wiederholen (Redo) möglich sein, kommt ein zweiter Stapel hinzu. Angenommen, ein Formular für Angebotstexte soll beides unterstützen:

class TextEditor {
  #text = '';
  #undo = new Stack();
  #redo = new Stack();

  get text() {
    return this.#text;
  }

  type(input) {
    this.#undo.push(this.#text);
    this.#text += input;
    this.#redo.clear(); // Neue Eingabe verwirft die Redo-Historie
  }

  undo() {
    if (this.#undo.isEmpty()) return;
    this.#redo.push(this.#text);
    this.#text = this.#undo.pop();
  }

  redo() {
    if (this.#redo.isEmpty()) return;
    this.#undo.push(this.#text);
    this.#text = this.#redo.pop();
  }
}

const editor = new TextEditor();
editor.type('Hallo');
editor.type(' Welt');
editor.undo();
console.log(editor.text); // 'Hallo'
editor.redo();
console.log(editor.text); // 'Hallo Welt'

Wichtig ist die Zeile in type(): Wer nach einem Undo neu tippt, hat einen anderen Weg eingeschlagen, und die alte Redo-Historie passt nicht mehr dazu. Das Beispiel speichert der Einfachheit halber komplette Textstände. Bei großen Dokumenten legen Editoren stattdessen Änderungsbefehle auf den Stapel, etwa die EditAction aus dem TypeScript-Beispiel, und wenden beim Rückgängigmachen deren Umkehrung an. Nach demselben Muster mit zwei Stapeln funktionieren auch Zurück und Vorwärts in einem Browser.

Klammern prüfen

Ob in einem Ausdruck alle Klammern korrekt geschlossen sind, lässt sich mit einem Stack in einem Durchgang prüfen. Jede öffnende Klammer kommt auf den Stapel. Jede schließende muss zur obersten passen:

const PAIRS = { ')': '(', ']': '[', '}': '{' };

function isBalanced(input) {
  const open = [];
  for (const char of input) {
    if (char === '(' || char === '[' || char === '{') {
      open.push(char);
    } else if (char in PAIRS) {
      if (open.pop() !== PAIRS[char]) return false;
    }
  }
  return open.length === 0;
}

console.log(isBalanced('if (a[0] === { x: 1 }.x) { run(); }')); // true
console.log(isBalanced('calc((1 + 2) * 3')); // false
console.log(isBalanced('list[0)]')); // false

Hier genügt ein schlichtes Array, eine eigene Klasse wäre für eine lokale Hilfsvariable übertrieben. Nach demselben Prinzip arbeiten Parser in Compilern, Formel-Editoren in Tabellenkalkulationen oder Prüfungen für verschachtelte Template-Tags.

Zahlen in andere Zahlensysteme umrechnen

Beim Umrechnen einer Dezimalzahl, etwa ins Binär- oder Hexadezimalsystem, entstehen die Ziffern in umgekehrter Reihenfolge: Die letzte Division liefert die erste Ziffer. Ein Stack dreht die Reihenfolge wieder um:

function toBase(value, base) {
  if (!Number.isSafeInteger(value) || value < 0) {
    throw new RangeError('Erwartet wird eine nicht negative ganze Zahl');
  }
  if (!Number.isInteger(base) || base < 2 || base > 36) {
    throw new RangeError('Die Basis muss zwischen 2 und 36 liegen');
  }
  if (value === 0) return '0';

  const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  const remainders = new Stack();
  while (value > 0) {
    remainders.push(value % base);
    value = Math.floor(value / base);
  }

  let result = '';
  while (!remainders.isEmpty()) {
    result += digits[remainders.pop()];
  }
  return result;
}

console.log(toBase(255, 16)); // 'FF'
console.log(toBase(10, 2)); // '1010'
console.log(toBase(0, 2)); // '0'

Die Sonderbehandlung für 0 ist nötig, weil die Schleife sonst gar nicht durchläuft und eine leere Zeichenkette zurückkäme. Für den Produktiveinsatz ist die Funktion allerdings überflüssig: JavaScript kann das bereits mit (255).toString(16), das Ergebnis ist 'ff' in Kleinbuchstaben. Das Beispiel taugt vor allem, um das Prinzip zu verstehen.

Tiefe Strukturen ohne Rekursion durchlaufen

Rekursive Funktionen nutzen den Call Stack. Ist die Struktur zu tief, droht der oben gezeigte RangeError. Ein eigener Stack verlagert die offene Arbeit vom Call Stack in ein gewöhnliches Array, dessen Größe nur durch den Arbeitsspeicher begrenzt ist:

function countFiles(root) {
  let count = 0;
  const pending = [root];
  while (pending.length > 0) {
    const node = pending.pop();
    if (node.children) {
      pending.push(...node.children);
    } else {
      count++;
    }
  }
  return count;
}

const tree = {
  name: 'projekt',
  children: [
    { name: 'README.md' },
    { name: 'src', children: [{ name: 'index.js' }, { name: 'util.js' }] },
  ],
};
console.log(countFiles(tree)); // 3

Diese Form heißt iterative Tiefensuche. Sie verarbeitet auch Bäume mit Hunderttausenden Ebenen, an denen die rekursive Variante scheitern würde. Ersetzt man den Stack durch eine Warteschlange, wird daraus eine Breitensuche, die einen Baum Ebene für Ebene abarbeitet.

Was das für Ihr Team bedeutet

Ein Stack ist kein Thema, für das ein Projekt eine Bibliothek braucht. Das Array bringt alles mit, und in vielen Fällen genügt es, ein lokales Array konsequent nur mit push() und pop() zu verwenden. Eine eigene Klasse lohnt sich, sobald der Stapel über Modulgrenzen hinweg weitergereicht wird oder fachliche Regeln hinzukommen, etwa eine Obergrenze für die Undo-Historie oder ein klar definiertes Verhalten bei leerem Stapel.

Überschätzt werden dagegen Mikro-Optimierungen wie die Objekt-Variante. Der größere Gewinn liegt in einer schmalen, gut typisierten Schnittstelle: Wer nur push, pop und peek anbietet, verhindert eine ganze Klasse von Fehlern, bei denen Code mitten in eine Historie oder einen Parser-Zustand greift. TypeScript macht diese Grenze für den Compiler sichtbar, und die Rückgabe T | undefined erzwingt die Prüfung auf den leeren Stapel.

Wer im Team solche Muster einheitlich umsetzen will, profitiert von gemeinsamen Regeln für Typen, Fehlerbehandlung und Code-Reviews. Darum geht es auf unserer Seite zu TypeScript-Codequalität mit Beratung, Coaching und Seminaren.

Häufige Fragen zum Stack in JavaScript

Braucht ein Projekt überhaupt eine eigene Stack-Klasse?

Nicht zwingend. Für lokale Algorithmen wie die Klammerprüfung reicht ein Array, das Sie nur mit push() und pop() verwenden. Eine Klasse ist sinnvoll, wenn mehrere Programmteile denselben Stapel nutzen und Sie verhindern wollen, dass jemand an der Schnittstelle vorbei auf die Elemente zugreift.

Wie verhält sich ein Stack bei sehr vielen Elementen?

push() und pop() bleiben auch bei großen Datenmengen schnell, weil sie nur das Ende des Arrays berühren. Begrenzend wirkt eher der Speicher: Jedes Element bleibt referenziert, bis es entnommen wird. Bei Undo-Historien ist daher eine Obergrenze üblich, ab der die ältesten Einträge verworfen werden. Weil die ältesten Einträge unten liegen, eignet sich dafür eine Deque besser als ein reiner Stack.

Ist ein Stack in JavaScript threadsicher?

JavaScript-Code läuft innerhalb eines Threads nacheinander ab, zwei Aufrufe von push() können sich dort also nicht überschneiden. Web Worker und Worker Threads in Node.js haben jeweils einen eigenen Speicher und tauschen Daten über Nachrichten aus, ein gemeinsamer Stack entsteht dabei nicht. Nur wer mit SharedArrayBuffer tatsächlich Speicher zwischen Threads teilt, muss Zugriffe selbst synchronisieren, etwa mit Atomics.

Was ist der Unterschied zwischen Stack und Heap?

Beide Begriffe tauchen im Zusammenhang mit Speicher auf, bezeichnen aber Verschiedenes. Der Call Stack verwaltet Funktionsaufrufe nach dem LIFO-Prinzip. Der Heap ist der Speicherbereich, in dem Objekte, Arrays und Funktionen liegen, solange sie erreichbar sind, und aus dem der Garbage Collector nicht mehr benötigte Objekte entfernt. Ein selbst gebauter Stack aus diesem Beitrag liegt übrigens als Array-Objekt im Heap.

Mehr aus „Programmiersprachen“

PHP-Migration nach PHP2Shell: Upgrade oder Sprachwechsel?

PHP2Shell und das Support-Ende von PHP 8.2: Was Sie jetzt patchen sollten, wie ein Upgrade auf 8.4 oder 8.5 gelingt und wann ein Sprachwechsel sinnvoll ist.

mehr erfahren

Rusts Lieferkette unter Beschuss: Warum ein Angriff nur der Anfang war

Ein Angriff auf Rust-Pakete war im August 2026 schnell gestoppt, das Grundproblem bleibt. Wie crates.io angreifbar ist und was Sie heute dagegen tun können.

mehr erfahren

Programmiersprachen und KI: Warum Rust für Code-Agenten so gut passt

KI-Agenten schreiben in Rust oft verlässlicheren Code, weil der Compiler viele Fehler sofort meldet. Was dahinter steckt und wo das Argument endet.

mehr erfahren

Microsoft und Rust: Was hinter dem Ziel „C und C++ bis 2030“ steckt

Microsoft nutzt Rust im Windows-Kernel, der Ersatz von C und C++ bis 2030 ist aber ein Forschungsziel. Was belegt ist und was es für Entwickler bedeutet.

mehr erfahren

Warum Python, Go und Rust die Zukunft der Softwareentwicklung prägen

Python, Go und Rust teilen sich die Arbeit: Daten und KI, Cloud-Dienste, sichere Systeme. Wo jede Sprache passt, wie sie zusammenwirken und was KI daran ändert.

mehr erfahren

Facebook und PHP: Vom Abschied über HHVM zu Hack

Ein Rückblick von 2025: Wie Facebook PHP mit HipHop, HHVM und Hack umbaute, warum es sich von PHP löste und was davon in PHP selbst ankam.

mehr erfahren

Weitere Blog-Artikel

Mockito in der Praxis: Unit-Tests für Java mit Mockito 5 und JUnit

Mockito 5 mit JUnit Jupiter: Wie Sie Mocks, Spies, ArgumentCaptor und statische Mocks einsetzen, Spring-Boot-Tests aufsetzen und Overmocking vermeiden.

mehr erfahren

Hibernate in Java: Leitfaden für den Datenbankzugriff mit ORM

Hibernate bildet Java-Objekte auf Tabellen ab. Sie erfahren, wie Entitäten, Transaktionen und Abfragen funktionieren und wie Sie N+1-Abfragen vermeiden.

mehr erfahren

Micro Frontends: Wann sich die Architektur für Webanwendungen lohnt

Micro Frontends teilen eine Weboberfläche auf mehrere Teams auf. Wann sich das lohnt, was es kostet und welche Alternativen Sie zuerst prüfen sollten.

mehr erfahren

Erlang: Wie Ericssons Telefonsprache Messaging-Dienste trägt

Erlang entstand bei Ericsson für Telefonvermittlungen und trägt heute Dienste wie WhatsApp. Wie Prozesse, Supervision und die BEAM funktionieren.

mehr erfahren

CUDA erklärt: Wie GPUs die KI-Entwicklung beschleunigen

CUDA macht Nvidia-GPUs für allgemeine Berechnungen nutzbar. Wie das funktioniert, warum KI darauf angewiesen ist und welche Alternativen es gibt.

mehr erfahren

JavaScript Decorators: Meta-Programmierung mit dem @-Zeichen

JavaScript Decorators erweitern Klassen, Methoden und Felder per @-Syntax. Sie erfahren, wie der TC39-Vorschlag funktioniert und wie Sie ihn heute einsetzen.

mehr erfahren

Aktuelle Blog-Artikel

PHP-Migration nach PHP2Shell: Upgrade oder Sprachwechsel?

PHP2Shell und das Support-Ende von PHP 8.2: Was Sie jetzt patchen sollten, wie ein Upgrade auf 8.4 oder 8.5 gelingt und wann ein Sprachwechsel sinnvoll ist.

mehr erfahren

Jev: Was ein KI-Modell für schnelles Denken anders macht als ChatGPT

Das System-1-KI-Modell Jev schreibt keinen Text, sondern beantwortet Fragen mit kalibrierten Wahrscheinlichkeiten. Wie das funktioniert und wofür es taugt.

mehr erfahren

Node.js ohne Ballast: 12 Bordmittel, die npm-Pakete ersetzen

Von fetch() über node:test bis Type Stripping: zwölf Node.js-Funktionen, die axios, dotenv, Jest und Co. ersetzen, mit Status in Node 24 und 26 und Grenzen.

mehr erfahren

KI-Agenten verstehen: MCP, A2A, AG-UI und A2UI einfach erklärt

MCP, A2A, AG-UI und A2UI verständlich erklärt: Wie KI-Agenten Werkzeuge nutzen, miteinander arbeiten und Oberflächen erzeugen – und wer die Standards betreut.

mehr erfahren

Rusts Lieferkette unter Beschuss: Warum ein Angriff nur der Anfang war

Ein Angriff auf Rust-Pakete war im August 2026 schnell gestoppt, das Grundproblem bleibt. Wie crates.io angreifbar ist und was Sie heute dagegen tun können.

mehr erfahren

Webentwicklung ohne SPA: Eine Web-App mit V, Veb, SQLite und htmx

Am Beispiel der Meetup-Plattform Clash zeigt sich, wie eine Web-App mit V, Veb, SQLite und htmx ohne SPA-Framework entsteht und wo der Ansatz an Grenzen stößt.

mehr erfahren

React-Performance: Warum weniger Optimierung mehr Tempo bringt

React-Performance heute: Wie Sie mit State am richtigen Ort, dem React Compiler, Transitions, Virtualisierung und Messung Ihre Anwendung spürbar beschleunigen.

mehr erfahren

React-Komponenten verbinden: Welcher Weg passt wann?

Props, Context, Zustand, TanStack Query, URL-Parameter oder Ereignisse: So wählen Sie den passenden Weg, damit zwei React-Komponenten Daten austauschen.

mehr erfahren

KI-Agenten in der Schleife: Loops in Claude Code und Codex

Was ein Loop bei KI-Agenten ist, welche Auslöser es gibt und wie Sie geplante Aufgaben in Claude Code und Codex mit Kostenkontrolle einrichten.

mehr erfahren

JavaScript 2026: Bun, Deno und TypeScript 7 läuten eine neue Ära ein

Node.js, Bun und Deno im Wettbewerb, TypeScript 7 mit Compiler in Go, Build-Werkzeuge in Rust: Was sich 2026 bei JavaScript ändert und was Sie davon übernehmen.

mehr erfahren

npm-Pakete sicher prüfen: So bewerten Sie ein Paket vor dem Einbau

npm-Pakete sicher prüfen: wie Sie Name, Wartung, Provenance, Install-Skripte, bekannte Lücken und Lizenz bewerten, bevor ein Paket in Ihr Projekt kommt.

mehr erfahren

npm install unter der Lupe: Wie Angreifer die Lieferkette kapern

Was npm install technisch tut, welche Angriffsmuster von Typosquatting bis Dependency Confusion es ausnutzen und wie Sie das Installieren absichern.

mehr erfahren

Programmiersprachen und KI: Warum Rust für Code-Agenten so gut passt

KI-Agenten schreiben in Rust oft verlässlicheren Code, weil der Compiler viele Fehler sofort meldet. Was dahinter steckt und wo das Argument endet.

mehr erfahren

Pi Agent vs. Claude Code: minimaler Open-Source-Agent im Vergleich

Pi Agent und Claude Code im Vergleich: Architektur, Erweiterungen, Modellwahl, Lizenz, Kosten und Sicherheit. Für wen sich der Open-Source-Agent lohnt.

mehr erfahren

Agentic Engine Optimization: Websites für KI-Agenten lesbar machen

Agentic Engine Optimization: Wie KI-Assistenten Ihre Website abrufen, welche Rolle robots.txt, llms.txt und strukturierte Daten spielen – und was belegt ist.

mehr erfahren

Claude Skills für Einsteiger: eigene KI-Workflows aufbauen

Claude Skills bündeln wiederkehrende Anweisungen in einer SKILL.md-Datei. So bauen Sie Skills auf und installieren sie in Claude und Claude Code.

mehr erfahren

Claude Code richtig nutzen: 15 Funktionen, die Profis kennen sollten

Claude Code kann mehr als chatten: So setzen Sie CLAUDE.md, Subagenten, Hooks, Skills, MCP und den Headless-Modus gezielt im Entwickleralltag ein.

mehr erfahren

Claude Code für Einsteiger: vom Terminal zur fertigen Anwendung

Claude Code arbeitet im Terminal direkt mit Ihren Dateien. So gelingen Installation, erste Aufträge, Planmodus, Skills und MCP auch ohne Programmiererfahrung.

mehr erfahren

OpenClaw im Praxistest: vom Chatbot zum digitalen Assistenten

OpenClaw macht ein Sprachmodell zum selbst gehosteten Agenten mit Zugriff auf Rechner und Messenger. Aufbau, Einrichtung, Skills und Sicherheitsregeln.

mehr erfahren

Das Ende der Menüs: Wie KI die digitale Arbeitsumgebung verändert

Seit Jahrzehnten bedienen wir Computer über Fenster, Menüs und Ordner. KI-Agenten verschieben das zu Aufträgen in Alltagssprache. Was sich ändert und was nicht.

mehr erfahren

Microsoft und Rust: Was hinter dem Ziel „C und C++ bis 2030“ steckt

Microsoft nutzt Rust im Windows-Kernel, der Ersatz von C und C++ bis 2030 ist aber ein Forschungsziel. Was belegt ist und was es für Entwickler bedeutet.

mehr erfahren

TanStack Start: Das React-Framework als Alternative zu Next.js

TanStack Start ist ein Fullstack-Framework für React auf Basis von TanStack Router und Vite. Was es kann und wann es eine Alternative zu Next.js ist.

mehr erfahren

Die Ralph-Wiggum-Technik: KI-Coding-Agenten, die nicht aufgeben

Die Ralph-Wiggum-Technik lässt einen Coding-Agenten denselben Auftrag wiederholen, bis die Tests bestehen. Wie sie funktioniert und worauf Sie achten sollten.

mehr erfahren

Warum KI Entwickler nicht ersetzt, aber ihre Rolle verändert

KI-Assistenten schreiben heute viel Code. Warum Fachwissen trotzdem wichtiger wird und welche Fähigkeiten Entwickler:innen jetzt gezielt ausbauen sollten.

mehr erfahren

Von Node.js zu Bun: Next.js-Projekte schrittweise umstellen

Wie Sie Bun in Next.js einsetzen: von bun install über bun --bun next dev bis zum Deployment. Was dabei schneller wird, was nicht und was Sie vorher prüfen.

mehr erfahren

Bun erklärt: JavaScript-Laufzeit, Paketmanager und Bundler in einem

Bun ist Laufzeitumgebung, Paketmanager, Bundler und Testrunner in einem. Wie es funktioniert, wie kompatibel es zu Node.js ist und für wen es sich lohnt.

mehr erfahren

KI-Agenten richtig anleiten: Spezifikationen, die funktionieren

Spezifikationen für KI-Coding-Agenten wie Claude Code oder GitHub Copilot: welche Angaben hineingehören, wie Sie Aufgaben aufteilen und Grenzen setzen.

mehr erfahren

Was ist .NET? Die Microsoft-Plattform einfach erklärt

.NET ist Microsofts quelloffene Entwicklungsplattform für Web, Cloud, Desktop und Apps. Sie erfahren, wie Laufzeit, SDK und Versionen zusammenhängen.

mehr erfahren

Künstliche Intelligenz 2026: Vom Chatbot zum digitalen Kollegen

Rückblick auf den KI-Ausblick vom Januar 2026: acht erwartete Trends von Multi-Agenten-Systemen über physische KI und EU AI Act bis zu Quanten-Utility.

mehr erfahren

KI-Jahr 2025: Vier Erkenntnisse und ein Ausblick auf 2026

Rückblick vom Januar 2026 auf das KI-Jahr 2025: vier Entwicklungen von unauffälligen Agenten bis zum Chipmangel und was sie damals für 2026 erwarten ließen.

mehr erfahren

REST und Event-Streams: Wann sich ereignisbasierte Backends lohnen

REST oder Event-Streams? Wie sich Request/Response und Publish/Subscribe unterscheiden, wann Kafka, SSE oder WebSockets passen und wo REST richtig bleibt.

mehr erfahren

Shai-Hulud 2.0: Wie sich ein Wurm im November 2025 durch npm fraß

Shai-Hulud 2.0 einfach erklärt: Rückblick auf den npm-Wurm vom November 2025, wie er Zugangsdaten stahl, sich selbst verbreitete und wie Sie sich schützten.

mehr erfahren

HTMX: Moderne Webanwendungen ohne JavaScript-Framework bauen

HTMX lädt Inhalte nach, sendet Formulare und tauscht Seitenteile per HTML-Attribut aus. Die Anleitung zeigt Browser- und Serverseite und den Stand von HTMX 4.

mehr erfahren

Electron vs. Tauri: Desktop-Apps mit Webtechnik im Vergleich

Electron bringt Chromium und Node.js mit, Tauri nutzt den Webview des Systems und einen Kern in Rust. Der Vergleich zeigt, wann sich welches Framework eignet.

mehr erfahren

Architekturkompetenz im KI-Zeitalter: Was Full-Stack heute heißt

Wenn KI-Werkzeuge Code schreiben, verschiebt sich die Arbeit zu Architekturentscheidungen. Welche Fähigkeiten zählen und wie Sie sie gezielt aufbauen.

mehr erfahren

Omarchy im Test: So macht Linux endlich wieder Spaß

Unser Test von Omarchy aus dem November 2025: Das Linux auf Basis von Arch und Hyprland setzt auf Tastatur, Kachelfenster und abgestimmte Themes.

mehr erfahren

JWT-Probleme: Warum Entwickler vor JSON Web Tokens warnen

JWT-Probleme im Überblick: Warum sich Tokens schwer widerrufen lassen, welche Prüffehler gefährlich sind und wann klassische Sessions die bessere Wahl sind.

mehr erfahren

7 KI-Begriffe erklärt: Von KI-Agenten bis Superintelligenz

Sieben KI-Begriffe von KI-Agenten über RAG und MCP bis Superintelligenz: was sie bedeuten, wie sie zusammenhängen und was davon für Unternehmen zählt.

mehr erfahren

Machine Learning verstehen: von den Grundlagen bis zu moderner KI

Machine Learning verständlich erklärt: welche Lernverfahren es gibt, wie Training mit Daten abläuft und wie Sie prüfen, ob ein Modell wirklich etwas taugt.

mehr erfahren

Scrum-Master-Rolle auf dem Prüfstand: ein Blick aus Architektursicht

Lohnt sich ein Scrum Master noch? Wir betrachten die Rolle aus Sicht der Softwarearchitektur, gleichen sie mit dem Scrum Guide 2020 ab und zeigen Alternativen.

mehr erfahren

Was dürfen wir für Sie tun?

So sind wir zu erreichen: