Skip to content
GreenSnippets

Encode and decode opaque pagination cursors

Turn a sort position into a URL-safe cursor string and validate it when it comes back from the client.

JavaScript
function encodeCursor(position) {
  return Buffer.from(JSON.stringify(position), "utf8").toString("base64url");
}

function decodeCursor(cursor) {
  try {
    const value = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
    const valid =
      value && typeof value === "object" && typeof value.id === "string" && typeof value.createdAt === "string";
    return valid ? { id: value.id, createdAt: value.createdAt } : null;
  } catch {
    return null;
  }
}

Example / expected output

Output
const next = encodeCursor({ id: "42", createdAt: "2025-01-01T00:00:00Z" });
decodeCursor(next); // { id: "42", createdAt: "2025-01-01T00:00:00Z" }

How it works

Opaque cursors let you change the pagination internals later and discourage clients from building them by hand. The cursor is base64url JSON of the last item's sort keys. Always treat a returned cursor as untrusted input: decode defensively, validate the fields and return null for anything malformed.