blob: abca5f62994820c51b874b031a57910a777daf7d [file] [log] [blame]
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Schema evolution and compatibility · Apache Pulsar</title><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="generator" content="Docusaurus"/><meta name="description" content="Normally, schemas do not stay the same over a long period of time. Instead, they undergo evolutions to satisfy new needs. "/><meta name="docsearch:version" content="2.8.0"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Schema evolution and compatibility · Apache Pulsar"/><meta property="og:type" content="website"/><meta property="og:url" content="https://pulsar.apache.org/"/><meta property="og:description" content="Normally, schemas do not stay the same over a long period of time. Instead, they undergo evolutions to satisfy new needs. "/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://pulsar.apache.org/img/pulsar.svg"/><link rel="shortcut icon" href="/img/pulsar.ico"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css"/><link rel="alternate" type="application/atom+xml" href="https://pulsar.apache.org/blog/atom.xml" title="Apache Pulsar Blog ATOM Feed"/><link rel="alternate" type="application/rss+xml" href="https://pulsar.apache.org/blog/feed.xml" title="Apache Pulsar Blog RSS Feed"/><link rel="stylesheet" href="/css/code-blocks-buttons.css"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script><script type="text/javascript" src="/js/custom.js"></script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/en"><img class="logo" src="/img/pulsar.svg" alt="Apache Pulsar"/></a><a href="/en/versions"><h3>2.8.0</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/en/2.8.0/getting-started-standalone" target="_self">Docs</a></li><li class=""><a href="/en/download" target="_self">Download</a></li><li class="siteNavGroupActive"><a href="/docs/en/2.8.0/client-libraries" target="_self">Clients</a></li><li class=""><a href="#restapis" target="_self">REST APIs</a></li><li class=""><a href="#cli" target="_self">Cli</a></li><li class=""><a href="/blog/" target="_self">Blog</a></li><li class=""><a href="#community" target="_self">Community</a></li><li class=""><a href="#apache" target="_self">Apache</a></li><li class=""><a href="https://pulsar-next.staged.apache.org/" target="_self">New Website (Beta)</a></li><span><li><a id="languages-menu" href="#"><img class="languages-icon" src="/img/language.svg" alt="Languages icon"/>English</a><div id="languages-dropdown" class="hide"><ul id="languages-dropdown-items"><li><a href="/docs/ja/2.8.0/schema-evolution-compatibility">日本語</a></li><li><a href="/docs/fr/2.8.0/schema-evolution-compatibility">Français</a></li><li><a href="/docs/ko/2.8.0/schema-evolution-compatibility">한국어</a></li><li><a href="/docs/zh-CN/2.8.0/schema-evolution-compatibility">中文</a></li><li><a href="/docs/zh-TW/2.8.0/schema-evolution-compatibility">繁體中文</a></li><li><a href="https://crowdin.com/project/apache-pulsar" target="_blank" rel="noreferrer noopener">Help Translate</a></li></ul></div></li><script>
const languagesMenuItem = document.getElementById("languages-menu");
const languagesDropDown = document.getElementById("languages-dropdown");
languagesMenuItem.addEventListener("click", function(event) {
event.preventDefault();
if (languagesDropDown.className == "hide") {
languagesDropDown.className = "visible";
} else {
languagesDropDown.className = "hide";
}
});
</script></span></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i></i><span>Pulsar Schema</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Get Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/getting-started-standalone">Run Pulsar locally</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/getting-started-docker">Run Pulsar in Docker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/getting-started-helm">Run Pulsar in Kubernetes</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Concepts and Architecture</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-messaging">Messaging</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-architecture-overview">Architecture</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-clients">Clients</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-replication">Geo Replication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-multi-tenancy">Multi Tenancy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-authentication">Authentication and Authorization</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-topic-compaction">Topic Compaction</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-proxy-sni-routing">Proxy support with SNI routing</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/concepts-multiple-advertised-listeners">Multiple advertised listeners</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar Schema</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/schema-get-started">Get started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/schema-understand">Understand schema</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/en/2.8.0/schema-evolution-compatibility">Schema evolution and compatibility</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/schema-manage">Manage schema</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar Functions</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-runtime">Setup: Configure Functions runtime</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-worker">Setup: Pulsar Functions Worker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-develop">How-to: Develop</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-package">How-to: Package</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-debug">How-to: Debug</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-deploy">How-to: Deploy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/functions-cli">Reference: CLI</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/window-functions-context">Window Functions: Context</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar IO</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-quickstart">Get started</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-use">Use</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-debug">Debug</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-connectors">Built-in connector</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-cdc">CDC connector</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-develop">Develop</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/io-cli">CLI</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Pulsar SQL</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/sql-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/sql-getting-started">Query data</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/sql-deployment-configurations">Configuration and deployment</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/sql-rest-api">REST APIs</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Tiered Storage</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/tiered-storage-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/tiered-storage-aws">AWS S3 offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/tiered-storage-gcs">GCS offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/tiered-storage-filesystem">Filesystem offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/tiered-storage-azure">Azure BlobStore offloader</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/tiered-storage-aliyun">Aliyun OSS offloader</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Transactions</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/txn-why">Why transactions?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/txn-what">What are transactions?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/txn-how">How transactions work?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/txn-use">How to use transactions?</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/txn-monitor">How to monitor transactions?</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Kubernetes (Helm)</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/helm-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/helm-prepare">Prepare</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/helm-install">Install</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/helm-deploy">Deployment</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/helm-upgrade">Upgrade</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/helm-tools">Required Tools</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Deployment</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/deploy-aws">Amazon Web Services</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/deploy-kubernetes">Kubernetes</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/deploy-bare-metal">Bare metal</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/deploy-bare-metal-multi-cluster">Bare metal multi-cluster</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/deploy-docker">Docker</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/deploy-monitoring">Monitor</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Administration</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-zk-bk">ZooKeeper and BookKeeper</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-geo">Geo-replication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-pulsar-manager">Pulsar Manager</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-stats">Pulsar statistics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-load-balance">Load balance</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-proxy">Pulsar proxy</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-upgrade">Upgrade</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/administration-isolation">Pulsar isolation</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Security</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-tls-transport">Transport Encryption using TLS</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-tls-authentication">Authentication using TLS</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-tls-keystore">Using TLS with KeyStore configure</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-jwt">Authentication using JWT</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-athenz">Authentication using Athenz</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-kerberos">Authentication using Kerberos</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-oauth2">Authentication using OAuth 2.0 access tokens</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-authorization">Authorization and ACLs</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-encryption">End-to-End Encryption</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-extending">Extending</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/security-bouncy-castle">Bouncy Castle Providers</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Performance</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/performance-pulsar-perf">Pulsar Perf</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Client Libraries</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-java">Java</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-go">Go</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-python">Python</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-cpp">C++</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-node">Node.js</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-websocket">WebSocket</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/client-libraries-dotnet">C#</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Admin API</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-overview">Overview</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-clusters">Clusters</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-tenants">Tenants</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-brokers">Brokers</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-namespaces">Namespaces</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-permissions">Permissions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-topics">Topics</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-functions">Functions</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/admin-api-packages">Packages</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Adaptors</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/adaptors-kafka">Kafka client wrapper</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/adaptors-spark">Apache Spark</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/adaptors-storm">Apache Storm</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Cookbooks</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-compaction">Topic compaction</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-deduplication">Message deduplication</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-non-persistent">Non-persistent messaging</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-retention-expiry">Message retention and expiry</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-encryption">Encryption</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-message-queue">Message queue</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/cookbooks-bookkeepermetadata">BookKeeper Ledger Metadata</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Development</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/develop-tools">Simulation tools</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/developing-binary-protocol">Binary protocol</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/develop-schema">Custom schema storage</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/develop-load-manager">Modular load manager</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Reference</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/reference-terminology">Terminology</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/reference-cli-tools">Pulsar CLI tools</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/reference-configuration">Pulsar configuration</a></li><li class="navListItem"><a class="navItem" href="/docs/en/2.8.0/reference-metrics">Pulsar Metrics</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/apache/pulsar/edit/master/site2/docs/schema-evolution-compatibility.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Schema evolution and compatibility</h1></header><article><div><span><p>Normally, schemas do not stay the same over a long period of time. Instead, they undergo evolutions to satisfy new needs.</p>
<p>This chapter examines how Pulsar schema evolves and what Pulsar schema compatibility check strategies are.</p>
<h2><a class="anchor" aria-hidden="true" id="schema-evolution"></a><a href="#schema-evolution" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Schema evolution</h2>
<p>Pulsar schema is defined in a data structure called <code>SchemaInfo</code>.</p>
<p>Each <code>SchemaInfo</code> stored with a topic has a version. The version is used to manage the schema changes happening within a topic.</p>
<p>The message produced with <code>SchemaInfo</code> is tagged with a schema version. When a message is consumed by a Pulsar client, the Pulsar client can use the schema version to retrieve the corresponding <code>SchemaInfo</code> and use the correct schema information to deserialize data.</p>
<h3><a class="anchor" aria-hidden="true" id="what-is-schema-evolution"></a><a href="#what-is-schema-evolution" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What is schema evolution?</h3>
<p>Schemas store the details of attributes and types. To satisfy new business requirements, you need to update schemas inevitably over time, which is called <strong>schema evolution</strong>.</p>
<p>Any schema changes affect downstream consumers. Schema evolution ensures that the downstream consumers can seamlessly handle data encoded with both old schemas and new schemas.</p>
<h3><a class="anchor" aria-hidden="true" id="how-pulsar-schema-should-evolve"></a><a href="#how-pulsar-schema-should-evolve" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How Pulsar schema should evolve?</h3>
<p>The answer is Pulsar schema compatibility check strategy. It determines how schema compares old schemas with new schemas in topics.</p>
<p>For more information, see <a href="#schema-compatibility-check-strategy">Schema compatibility check strategy</a>.</p>
<h3><a class="anchor" aria-hidden="true" id="how-does-pulsar-support-schema-evolution"></a><a href="#how-does-pulsar-support-schema-evolution" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How does Pulsar support schema evolution?</h3>
<ol>
<li><p>When a producer/consumer/reader connects to a broker, the broker deploys the schema compatibility checker configured by <code>schemaRegistryCompatibilityCheckers</code> to enforce schema compatibility check.</p>
<p>The schema compatibility checker is one instance per schema type.</p>
<p>Currently, Avro and JSON have their own compatibility checkers, while all the other schema types share the default compatibility checker which disables schema evolution.</p></li>
<li><p>The producer/consumer/reader sends its client <code>SchemaInfo</code> to the broker.</p></li>
<li><p>The broker knows the schema type and locates the schema compatibility checker for that type.</p></li>
<li><p>The broker uses the checker to check if the <code>SchemaInfo</code> is compatible with the latest schema of the topic by applying its compatibility check strategy.</p>
<p>Currently, the compatibility check strategy is configured at the namespace level and applied to all the topics within that namespace.</p></li>
</ol>
<h2><a class="anchor" aria-hidden="true" id="schema-compatibility-check-strategy"></a><a href="#schema-compatibility-check-strategy" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Schema compatibility check strategy</h2>
<p>Pulsar has 8 schema compatibility check strategies, which are summarized in the following table.</p>
<p>Suppose that you have a topic containing three schemas (V1, V2, and V3), V1 is the oldest and V3 is the latest:</p>
<table style="table">
<tr>
<th>
<p>Compatibility check strategy</p>
</th>
<th>
<p>Definition</p>
</th>
<th>
<p>Changes allowed</p>
</th>
<th>
<p>Check against which schema</p>
</th>
<th>
<p>Upgrade first</p>
</th>
</tr>
<tr>
<td>
<p><code>ALWAYS_COMPATIBLE</code></p>
</td>
<td>
<p>Disable schema compatibility check.</p>
</td>
<td>
<p>All changes are allowed</p>
</td>
<td>
<p>All previous versions</p>
</td>
<td>
<p>Any order</p>
</td>
</tr>
<tr>
<td>
<p><code>ALWAYS_INCOMPATIBLE</code></p>
</td>
<td>
<p>Disable schema evolution.</p>
</td>
<td>
<p>All changes are disabled</p>
</td>
<td>
<p>None</p>
</td>
<td>
<p>None</p>
</td>
</tr>
<tr>
<td>
<p><code>BACKWARD</code></p>
</td>
<td>
<p>Consumers using the schema V3 can process data written by producers using the schema V3 or V2.</p>
</td>
<td>
<ul>
<li><p>Add optional fields</p></li>
<li><p>Delete fields</p></li>
</ul>
</td>
<td>
<p>Latest version</p>
</td>
<td>
<p>Consumers</p>
</td>
</tr>
<tr>
<td>
<p><code>BACKWARD_TRANSITIVE</code></p>
</td>
<td>
<p>Consumers using the schema V3 can process data written by producers using the schema V3, V2 or V1.</p>
</td>
<td>
<ul>
<li><p>Add optional fields</p></li>
<li><p>Delete fields</p></li>
</ul>
</td>
<td>
<p>All previous versions</p>
</td>
<td>
<p>Consumers</p>
</td>
</tr>
<tr>
<td>
<p><code>FORWARD</code></p>
</td>
<td>
<p>Consumers using the schema V3 or V2 can process data written by producers using the schema V3.</p>
</td>
<td>
<ul>
<li><p>Add fields</p></li>
<li><p>Delete optional fields</p></li>
</ul>
</td>
<td>
<p>Latest version</p>
</td>
<td>
<p>Producers</p>
</td>
</tr>
<tr>
<td>
<p><code>FORWARD_TRANSITIVE</code></p>
</td>
<td>
<p>Consumers using the schema V3, V2 or V1 can process data written by producers using the schema V3.</p>
</td>
<td>
<ul>
<li><p>Add fields</p></li>
<li><p>Delete optional fields</p></li>
</ul>
</td>
<td>
<p>All previous versions</p>
</td>
<td>
<p>Producers</p>
</td>
</tr>
<tr>
<td>
<p><code>FULL</code></p>
</td>
<td>
<p>Backward and forward compatible between the schema V3 and V2.</p>
</td>
<td>
<ul>
<li>Modify optional fields</li>
</ul>
</td>
<td>
<p>Latest version</p>
</td>
<td>
<p>Any order</p>
</td>
</tr>
<tr>
<td>
<p><code>FULL_TRANSITIVE</code></p>
</td>
<td>
<p>Backward and forward compatible among the schema V3, V2, and V1.</p>
</td>
<td>
<ul>
<li>Modify optional fields</li>
</ul>
</td>
<td>
<p>All previous versions</p>
</td>
<td>
<p>Any order</p>
</td>
</tr>
</table>
<h3><a class="anchor" aria-hidden="true" id="always_compatible-and-always_incompatible"></a><a href="#always_compatible-and-always_incompatible" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>ALWAYS_COMPATIBLE and ALWAYS_INCOMPATIBLE</h3>
<table style="table">
<tr>
<th>
<p>Compatibility check strategy</p>
</th>
<th>
<p>Definition</p>
</th>
<th>
<p>Note</p>
</th>
</tr>
<tr>
<td>
<p><code>ALWAYS_COMPATIBLE</code></p>
</td>
<td>
<p>Disable schema compatibility check.</p>
</td>
<td>
<p>None</p>
</td>
</tr>
<tr>
<td>
<p><code>ALWAYS_INCOMPATIBLE</code></p>
</td>
<td>
<p>Disable schema evolution, that is, any schema change is rejected.</p>
</td>
<td>
<ul>
<li><p>For all schema types except Avro and JSON, the default schema compatibility check strategy is <code>ALWAYS_INCOMPATIBLE</code>.</p></li>
<li><p>For Avro and JSON, the default schema compatibility check strategy is <code>FULL</code>.</p></li>
</ul>
</td>
</tr>
</table>
<h4><a class="anchor" aria-hidden="true" id="example"></a><a href="#example" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Example</h4>
<ul>
<li><p>Example 1</p>
<p>In some situations, an application needs to store events of several different types in the same Pulsar topic.</p>
<p>In particular, when developing a data model in an <code>Event Sourcing</code> style, you might have several kinds of events that affect the state of an entity.</p>
<p>For example, for a user entity, there are <code>userCreated</code>, <code>userAddressChanged</code> and <code>userEnquiryReceived</code> events. The application requires that those events are always read in the same order.</p>
<p>Consequently, those events need to go in the same Pulsar partition to maintain order. This application can use <code>ALWAYS_COMPATIBLE</code> to allow different kinds of events co-exist in the same topic.</p></li>
<li><p>Example 2</p>
<p>Sometimes we also make incompatible changes.</p>
<p>For example, you are modifying a field type from <code>string</code> to <code>int</code>.</p>
<p>In this case, you need to:</p>
<ul>
<li><p>Upgrade all producers and consumers to the new schema versions at the same time.</p></li>
<li><p>Optionally, create a new topic and start migrating applications to use the new topic and the new schema, avoiding the need to handle two incompatible versions in the same topic.</p></li>
</ul></li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="backward-and-backward_transitive"></a><a href="#backward-and-backward_transitive" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>BACKWARD and BACKWARD_TRANSITIVE</h3>
<p>Suppose that you have a topic containing three schemas (V1, V2, and V3), V1 is the oldest and V3 is the latest:</p>
<table>
<thead>
<tr><th>Compatibility check strategy</th><th>Definition</th><th>Description</th></tr>
</thead>
<tbody>
<tr><td><code>BACKWARD</code></td><td>Consumers using the new schema can process data written by producers using the <strong>last schema</strong>.</td><td>The consumers using the schema V3 can process data written by producers using the schema V3 or V2.</td></tr>
<tr><td><code>BACKWARD_TRANSITIVE</code></td><td>Consumers using the new schema can process data written by producers using <strong>all previous schemas</strong>.</td><td>The consumers using the schema V3 can process data written by producers using the schema V3, V2, or V1.</td></tr>
</tbody>
</table>
<h4><a class="anchor" aria-hidden="true" id="example-1"></a><a href="#example-1" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Example</h4>
<ul>
<li><p>Example 1</p>
<p>Remove a field.</p>
<p>A consumer constructed to process events without one field can process events written with the old schema containing the field, and the consumer will ignore that field.</p></li>
<li><p>Example 2</p>
<p>You want to load all Pulsar data into a Hive data warehouse and run SQL queries against the data.</p>
<p>Same SQL queries must continue to work even the data is changed. To support it, you can evolve the schemas using the <code>BACKWARD</code> strategy.</p></li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="forward-and-forward_transitive"></a><a href="#forward-and-forward_transitive" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>FORWARD and FORWARD_TRANSITIVE</h3>
<p>Suppose that you have a topic containing three schemas (V1, V2, and V3), V1 is the oldest and V3 is the latest:</p>
<table>
<thead>
<tr><th>Compatibility check strategy</th><th>Definition</th><th>Description</th></tr>
</thead>
<tbody>
<tr><td><code>FORWARD</code></td><td>Consumers using the <strong>last schema</strong> can process data written by producers using a new schema, even though they may not be able to use the full capabilities of the new schema.</td><td>The consumers using the schema V3 or V2 can process data written by producers using the schema V3.</td></tr>
<tr><td><code>FORWARD_TRANSITIVE</code></td><td>Consumers using <strong>all previous schemas</strong> can process data written by producers using a new schema.</td><td>The consumers using the schema V3, V2, or V1 can process data written by producers using the schema V3.</td></tr>
</tbody>
</table>
<h4><a class="anchor" aria-hidden="true" id="example-2"></a><a href="#example-2" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Example</h4>
<ul>
<li><p>Example 1</p>
<p>Add a field.</p>
<p>In most data formats, consumers written to process events without new fields can continue doing so even when they receive new events containing new fields.</p></li>
<li><p>Example 2</p>
<p>If a consumer has an application logic tied to a full version of a schema, the application logic may not be updated instantly when the schema evolves.</p>
<p>In this case, you need to project data with a new schema onto an old schema that the application understands.</p>
<p>Consequently, you can evolve the schemas using the <code>FORWARD</code> strategy to ensure that the old schema can process data encoded with the new schema.</p></li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="full-and-full_transitive"></a><a href="#full-and-full_transitive" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>FULL and FULL_TRANSITIVE</h3>
<p>Suppose that you have a topic containing three schemas (V1, V2, and V3), V1 is the oldest and V3 is the latest:</p>
<table style="table">
<tr>
<th>
<p>Compatibility check strategy</p>
</th>
<th>
<p>Definition</p>
</th>
<th>
<p>Description</p>
</th>
<th>
<p>Note</p>
</th>
</tr>
<tr>
<td>
<p><code>FULL</code></p>
</td>
<td>
<p>Schemas are both backward and forward compatible, which means:</p>
<p>Consumers using the last schema can process data written by producers using the new schema.</p>
<p>AND</p>
<p>Consumers using the new schema can process data written by producers using the last schema.</p>
</td>
<td>
<p>Consumers using the schema V3 can process data written by producers using the schema V3 or V2.</p>
<p>AND</p>
<p>Consumers using the schema V3 or V2 can process data written by producers using the schema V3.</p>
</td>
<td>
<ul>
<li><p>For Avro and JSON, the default schema compatibility check strategy is <code>FULL</code>.</p></li>
<li><p>For all schema types except Avro and JSON, the default schema compatibility check strategy is <code>ALWAYS_INCOMPATIBLE</code>.</p></li>
</ul>
</td>
</tr>
<tr>
<td>
<p><code>FULL_TRANSITIVE</code></p>
</td>
<td>
<p>The new schema is backward and forward compatible with all previously registered schemas.</p>
</td>
<td>
<p>Consumers using the schema V3 can process data written by producers using the schema V3, V2 or V1.</p>
<p>AND</p>
<p>Consumers using the schema V3, V2 or V1 can process data written by producers using the schema V3.</p>
</td>
<td>
<p>None</p>
</td>
</tr>
</table>
<h4><a class="anchor" aria-hidden="true" id="example-3"></a><a href="#example-3" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Example</h4>
<p>In some data formats, for example, Avro, you can define fields with default values. Consequently, adding or removing a field with a default value is a fully compatible change.</p>
<h2><a class="anchor" aria-hidden="true" id="schema-verification"></a><a href="#schema-verification" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Schema verification</h2>
<p>When a producer or a consumer tries to connect to a topic, a broker performs some checks to verify a schema.</p>
<h3><a class="anchor" aria-hidden="true" id="producer"></a><a href="#producer" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Producer</h3>
<p>When a producer tries to connect to a topic (suppose ignore the schema auto creation), a broker does the following checks:</p>
<ul>
<li><p>Check if the schema carried by the producer exists in the schema registry or not.</p>
<ul>
<li><p>If the schema is already registered, then the producer is connected to a broker and produce messages with that schema.</p></li>
<li><p>If the schema is not registered, then Pulsar verifies if the schema is allowed to be registered based on the configured compatibility check strategy.</p></li>
</ul></li>
</ul>
<h3><a class="anchor" aria-hidden="true" id="consumer"></a><a href="#consumer" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Consumer</h3>
<p>When a consumer tries to connect to a topic, a broker checks if a carried schema is compatible with a registered schema based on the configured schema compatibility check strategy.</p>
<table style="table">
<tr>
<th>
<p>Compatibility check strategy</p>
</th>
<th>
<p>Check logic</p>
</th>
</tr>
<tr>
<td>
<p><code>ALWAYS_COMPATIBLE</code></p>
</td>
<td>
<p>All pass</p>
</td>
</tr>
<tr>
<td>
<p><code>ALWAYS_INCOMPATIBLE</code></p>
</td>
<td>
<p>No pass</p>
</td>
</tr>
<tr>
<td>
<p><code>BACKWARD</code></p>
</td>
<td>
<p>Can read the last schema</p>
</td>
</tr>
<tr>
<td>
<p><code>BACKWARD_TRANSITIVE</code></p>
</td>
<td>
<p>Can read all schemas</p>
</td>
</tr>
<tr>
<td>
<p><code>FORWARD</code></p>
</td>
<td>
<p>Can read the last schema</p>
</td>
</tr>
<tr>
<td>
<p><code>FORWARD_TRANSITIVE</code></p>
</td>
<td>
<p>Can read the last schema</p>
</td>
</tr>
<tr>
<td>
<p><code>FULL</code></p>
</td>
<td>
<p>Can read the last schema</p>
</td>
</tr>
<tr>
<td>
<p><code>FULL_TRANSITIVE</code></p>
</td>
<td>
<p>Can read all schemas</p>
</td>
</tr>
</table>
<h2><a class="anchor" aria-hidden="true" id="order-of-upgrading-clients"></a><a href="#order-of-upgrading-clients" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Order of upgrading clients</h2>
<p>The order of upgrading client applications is determined by the compatibility check strategy.</p>
<p>For example, the producers using schemas to write data to Pulsar and the consumers using schemas to read data from Pulsar.</p>
<table style="table">
<tr>
<th>
<p>Compatibility check strategy</p>
</th>
<th>
<p>Upgrade first</p>
</th>
<th>
<p>Description</p>
</th>
</tr>
<tr>
<td>
<p><code>ALWAYS_COMPATIBLE</code></p>
</td>
<td>
<p>Any order</p>
</td>
<td>
<p>The compatibility check is disabled.</p>
<p>Consequently, you can upgrade the producers and consumers in <strong>any order</strong>.</p>
</td>
</tr>
<tr>
<td>
<p><code>ALWAYS_INCOMPATIBLE</code></p>
</td>
<td>
<p>None</p>
</td>
<td>
<p>The schema evolution is disabled.</p>
</td>
</tr>
<tr>
<td>
<ul>
<li><p><code>BACKWARD</code></p></li>
<li><p><code>BACKWARD_TRANSITIVE</code></p></li>
</ul>
</td>
<td>
<p>Consumers</p>
</td>
<td>
<p>There is no guarantee that consumers using the old schema can read data produced using the new schema.</p>
<p>Consequently, <strong>upgrade all consumers first</strong>, and then start producing new data.</p>
</td>
</tr>
<tr>
<td>
<ul>
<li><p><code>FORWARD</code></p></li>
<li><p><code>FORWARD_TRANSITIVE</code></p></li>
</ul>
</td>
<td>
<p>Producers</p>
</td>
<td>
<p>There is no guarantee that consumers using the new schema can read data produced using the old schema.</p>
<p>Consequently, <strong>upgrade all producers first</strong> to use the new schema and ensure that the data already produced using the old schemas are not available to consumers, and then upgrade the consumers.</p>
</td>
</tr>
<tr>
<td>
<ul>
<li><p><code>FULL</code></p></li>
<li><p><code>FULL_TRANSITIVE</code></p></li>
</ul>
</td>
<td>
<p>Any order</p>
</td>
<td>
<p>There is no guarantee that consumers using the old schema can read data produced using the new schema and consumers using the new schema can read data produced using the old schema.</p>
<p>Consequently, you can upgrade the producers and consumers in <strong>any order</strong>.</p>
</td>
</tr>
</table>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/en/2.8.0/schema-understand"><span class="arrow-prev"></span><span>Understand schema</span></a><a class="docs-next button" href="/docs/en/2.8.0/schema-manage"><span>Manage schema</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#schema-evolution">Schema evolution</a><ul class="toc-headings"><li><a href="#what-is-schema-evolution">What is schema evolution?</a></li><li><a href="#how-pulsar-schema-should-evolve">How Pulsar schema should evolve?</a></li><li><a href="#how-does-pulsar-support-schema-evolution">How does Pulsar support schema evolution?</a></li></ul></li><li><a href="#schema-compatibility-check-strategy">Schema compatibility check strategy</a><ul class="toc-headings"><li><a href="#always_compatible-and-always_incompatible">ALWAYS_COMPATIBLE and ALWAYS_INCOMPATIBLE</a></li><li><a href="#backward-and-backward_transitive">BACKWARD and BACKWARD_TRANSITIVE</a></li><li><a href="#forward-and-forward_transitive">FORWARD and FORWARD_TRANSITIVE</a></li><li><a href="#full-and-full_transitive">FULL and FULL_TRANSITIVE</a></li></ul></li><li><a href="#schema-verification">Schema verification</a><ul class="toc-headings"><li><a href="#producer">Producer</a></li><li><a href="#consumer">Consumer</a></li></ul></li><li><a href="#order-of-upgrading-clients">Order of upgrading clients</a></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="copyright">Copyright © 2022 The Apache Software Foundation. All Rights Reserved. Apache, Apache Pulsar and the Apache feather logo are trademarks of The Apache Software Foundation.</section><span><script>
const community = document.querySelector("a[href='#community']").parentNode;
const communityMenu =
'<li>' +
'<a id="community-menu" href="#">Community <span style="font-size: 0.75em">&nbsp;▼</span></a>' +
'<div id="community-dropdown" class="hide">' +
'<ul id="community-dropdown-items">' +
'<li><a href="/en/contact">Contact</a></li>' +
'<li><a href="/en/contributing">Contributing</a></li>' +
'<li><a href="/en/coding-guide">Coding guide</a></li>' +
'<li><a href="/en/events">Events</a></li>' +
'<li><a href="https://twitter.com/Apache_Pulsar" target="_blank">Twitter &#x2750</a></li>' +
'<li><a href="https://github.com/apache/pulsar/wiki" target="_blank">Wiki &#x2750</a></li>' +
'<li><a href="https://github.com/apache/pulsar/issues" target="_blank">Issue tracking &#x2750</a></li>' +
'<li><a href="https://pulsar-summit.org/" target="_blank">Pulsar Summit &#x2750</a></li>' +
'<li>&nbsp;</li>' +
'<li><a href="/en/resources">Resources</a></li>' +
'<li><a href="/en/team">Team</a></li>' +
'<li><a href="/en/powered-by">Powered By</a></li>' +
'</ul>' +
'</div>' +
'</li>';
community.innerHTML = communityMenu;
const communityMenuItem = document.getElementById("community-menu");
const communityDropDown = document.getElementById("community-dropdown");
communityMenuItem.addEventListener("click", function(event) {
event.preventDefault();
if (communityDropDown.className == 'hide') {
communityDropDown.className = 'visible';
} else {
communityDropDown.className = 'hide';
}
});
</script></span></footer></div><script>window.twttr=(function(d,s, id){var js,fjs=d.getElementsByTagName(s)[0],t=window.twttr||{};if(d.getElementById(id))return t;js=d.createElement(s);js.id=id;js.src='https://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js, fjs);t._e = [];t.ready = function(f) {t._e.push(f);};return t;}(document, 'script', 'twitter-wjs'));</script></body></html>