File size: 43,195 Bytes
3faeccf
31be352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3faeccf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CockroachDB Migration 2026 — check your sql for free</title>
<meta name="description" content="This free browser tool flags CockroachDB SQL statements that YSQL rejects or changes, along with licence-key and telemetry settings.">
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
</style>
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/yugabytedb-migration-check"><style data-yj-mfit="1">#out{max-width:100%}#out td,#out th{overflow-wrap:anywhere}#out pre,#out code{white-space:pre-wrap;overflow-wrap:anywhere}@media (max-width:640px){table{display:block;max-width:100%;overflow-x:auto}pre{max-width:100%;overflow-x:auto}code,a{overflow-wrap:anywhere}img,svg,video,canvas,iframe{max-width:100%}textarea,input,select{max-width:100%;box-sizing:border-box}.yj-lgbar{position:static!important;justify-content:flex-end;margin:0 0 10px}h1,h2,h3,h4,p,li,dd,dt,blockquote,figcaption,summary,label,.res,.lead{overflow-wrap:anywhere}label{max-width:100%;box-sizing:border-box}#out table:not(:has(tr>:nth-child(4))){display:table;table-layout:fixed;width:100%}#out table:has(tr>:nth-child(4)),#out table:has(tr>:nth-child(4)) tbody,#out table:has(tr>:nth-child(4)) tr,#out table:has(tr>:nth-child(4)) td{display:block;width:auto;overflow:visible}#out table:has(tr>:nth-child(4)) thead{display:none}#out table:has(tr>:nth-child(4)) tr{padding:10px 0;border-bottom:1px solid rgba(128,128,128,.28)}#out table:has(tr>:nth-child(4)) td{border:0;padding:1px 0}#out table:has(tr>:nth-child(4)) td:nth-child(-n+3){display:inline-block;margin-right:10px;font-size:12px;opacity:.78}}</style>
</head>
<body>
<div class="wrap">
<h1>CockroachDB Migration 2026 — check your sql for free</h1>
<p class="lede">YugabyteDB migration check for CockroachDB .sql files: flags 25 statements YSQL rejects or changes (UPSERT, unique_rowid, STRING, 64-bit INT, inline INDEX) plus licence-key and telemetry settings. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false">-- orders schema, exported from a CockroachDB 24.1 cluster
SET CLUSTER SETTING diagnostics.reporting.enabled = false;

CREATE TABLE orders (
  id INT PRIMARY KEY DEFAULT unique_rowid(),
  customer_id UUID NOT NULL,
  status STRING NOT NULL DEFAULT 'new',
  total DECIMAL(12,2) NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  INDEX orders_customer_idx (customer_id)
);

UPSERT INTO orders (id, customer_id, status, total)
VALUES (1, '4f1c2b7e-0d5a-4c1e-9b3a-2f6e8d7c1a90', 'paid', 42.00);</textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Check one CockroachDB .sql file and get every line YugabyteDB YSQL rejects or reads differently, with the rewrite for each line.. <strong>In the editor:</strong> Scan every .sql migration in the workspace in one pass and export the findings as a Markdown migration report for the change ticket. — that part asks for a licence key.</div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var YB_RULES = [
 {"id": "licence-image", "sev": "error", "scope": "image", "pattern": "cockroachdb/cockroach(?:-unstable)?:(v?\\d+\\.\\d+[\\w.\\-]*|latest)\\b", "msg": "This CockroachDB image falls under the CockroachDB Software License (from 24.3.0 on 2024-11-18, and 23.1-24.2 patches released from that date): a cluster without a key gets a 7-day grace, then is throttled to 5 concurrent open SQL transactions. Enterprise Free covers only businesses under $10M annual revenue", "fix": "plan the YugabyteDB cut-over before the next upgrade, or budget the Enterprise licence"},
 {"id": "licence-key-setting", "sev": "error", "pattern": "\\bSET\\s+CLUSTER\\s+SETTING\\s+(?:enterprise\\.license|cluster\\.organization)\\b", "msg": "Licence key in a migration file: under the CockroachDB Software License the key is renewed yearly (Enterprise Free) and a keyless cluster is throttled after a 7-day grace", "fix": "YugabyteDB is Apache-2.0, delete the statement on the YSQL side"},
 {"id": "licence-telemetry-off", "sev": "error", "pattern": "\\bSET\\s+CLUSTER\\s+SETTING\\s+diagnostics\\.reporting\\.enabled\\s*=\\s*(?:false|off|0)\\b", "msg": "Telemetry switched off: an Enterprise Free or Trial cluster is throttled after 7 days without sending telemetry", "fix": "delete the statement; YugabyteDB has no telemetry-for-licence rule"},
 {"id": "cluster-setting", "sev": "warn", "pattern": "\\bSET\\s+CLUSTER\\s+SETTING\\s+(?!enterprise\\.license|cluster\\.organization|diagnostics\\.reporting\\.enabled)", "msg": "SET CLUSTER SETTING is CockroachDB-only SQL", "fix": "move the setting to yb-master / yb-tserver flags"},
 {"id": "upsert", "sev": "error", "pattern": "\\bUPSERT\\s+INTO\\b", "msg": "UPSERT INTO does not exist in YSQL", "fix": "INSERT ... ON CONFLICT (pk) DO UPDATE SET col = EXCLUDED.col"},
 {"id": "unique-rowid", "sev": "error", "pattern": "\\bunique_rowid\\s*\\(", "msg": "unique_rowid() is a CockroachDB built-in; YSQL has no such function", "fix": "BIGINT GENERATED BY DEFAULT AS IDENTITY, or a sequence"},
 {"id": "string-type", "sev": "error", "pattern": "\\bSTRING\\b", "msg": "STRING is a CockroachDB type alias; YSQL has no STRING type", "fix": "TEXT (or VARCHAR(n))"},
 {"id": "bytes-type", "sev": "error", "pattern": "\\bBYTES\\b", "msg": "BYTES is a CockroachDB type alias; YSQL has no BYTES type", "fix": "BYTEA"},
 {"id": "int-width", "sev": "error", "pattern": "\\bINT(?:EGER)?\\b", "msg": "INT is 64-bit in CockroachDB but 32-bit in YSQL: values above 2,147,483,647 overflow after the move", "fix": "BIGINT (or INT8)"},
 {"id": "serial-width", "sev": "warn", "pattern": "\\bSERIAL\\b", "msg": "CockroachDB SERIAL defaults to a 64-bit unique_rowid() value; YSQL SERIAL is a 32-bit sequence", "fix": "BIGSERIAL or BIGINT GENERATED BY DEFAULT AS IDENTITY"},
 {"id": "hash-sharded-index", "sev": "error", "pattern": "\\)\\s*USING\\s+HASH\\b|\\bbucket_count\\b", "msg": "Hash-sharded index syntax (USING HASH after the column list, bucket_count) is CockroachDB-only", "fix": "declare the hash column in the key: PRIMARY KEY (id HASH)"},
 {"id": "column-family", "sev": "error", "pattern": "\\bFAMILY\\s+\\w*\\s*\\(", "msg": "Column families (FAMILY) are CockroachDB-only", "fix": "drop the FAMILY clauses"},
 {"id": "inline-index", "sev": "error", "pattern": "[,(]\\s*(?:UNIQUE\\s+|INVERTED\\s+)?INDEX\\s+\\w", "msg": "INDEX inside CREATE TABLE is CockroachDB syntax; YSQL rejects it", "fix": "a separate CREATE INDEX ... ON table (cols) statement"},
 {"id": "inverted-index", "sev": "error", "pattern": "\\bINVERTED\\s+INDEX\\b", "msg": "INVERTED INDEX is CockroachDB syntax", "fix": "CREATE INDEX ... USING GIN (col)"},
 {"id": "storing-clause", "sev": "error", "pattern": "\\bSTORING\\s*\\(", "msg": "STORING (...) is CockroachDB syntax for covering columns", "fix": "INCLUDE (...)"},
 {"id": "as-of-system-time", "sev": "error", "pattern": "\\bAS\\s+OF\\s+SYSTEM\\s+TIME\\b", "msg": "AS OF SYSTEM TIME is CockroachDB-only", "fix": "drop the clause; use follower reads settings on the YSQL session"},
 {"id": "configure-zone", "sev": "error", "pattern": "\\bCONFIGURE\\s+ZONE\\b", "msg": "CONFIGURE ZONE replica rules are CockroachDB-only", "fix": "CREATE TABLESPACE ... WITH (replica_placement = '...')"},
 {"id": "multi-region-locality", "sev": "error", "pattern": "\\bLOCALITY\\s+(?:REGIONAL|GLOBAL)\\b|\\bPRIMARY\\s+REGION\\b|\\bADD\\s+REGION\\b|\\bSURVIVE\\s+(?:ZONE|REGION)\\s+FAILURE\\b", "msg": "Multi-region SQL (LOCALITY, PRIMARY REGION, SURVIVE) is CockroachDB-only", "fix": "tablespaces with replica_placement per region"},
 {"id": "changefeed", "sev": "error", "pattern": "\\b(?:CREATE|EXPERIMENTAL)\\s+CHANGEFEED\\b", "msg": "CHANGEFEED is CockroachDB-only", "fix": "a YugabyteDB CDC stream, set up outside the schema file"},
 {"id": "crdb-internal", "sev": "error", "pattern": "\\bcrdb_internal\\.", "msg": "crdb_internal is a CockroachDB system schema", "fix": "pg_catalog or information_schema"},
 {"id": "split-at", "sev": "warn", "pattern": "\\bALTER\\s+(?:TABLE|INDEX)\\s+[^;]*?\\b(?:SPLIT\\s+AT|UNSPLIT|SCATTER)\\b", "msg": "ALTER ... SPLIT AT / SCATTER is CockroachDB range management", "fix": "CREATE TABLE ... SPLIT INTO n TABLETS"},
 {"id": "bulk-io", "sev": "error", "pattern": "\\bIMPORT\\s+(?:INTO|TABLE)\\b|\\bBACKUP\\s+(?:INTO|DATABASE|TABLE)\\b|\\bRESTORE\\s+(?:DATABASE|TABLE|FROM)\\b", "msg": "IMPORT / BACKUP / RESTORE are CockroachDB statements", "fix": "COPY ... FROM, ysql_dump, or yb-voyager"},
 {"id": "alter-primary-key", "sev": "error", "pattern": "\\bALTER\\s+PRIMARY\\s+KEY\\b", "msg": "ALTER PRIMARY KEY is CockroachDB-only", "fix": "recreate the table with the new key and copy the rows"},
 {"id": "on-update-expr", "sev": "error", "pattern": "\\bON\\s+UPDATE\\s+(?!CASCADE\\b|RESTRICT\\b|SET\\s+(?:NULL|DEFAULT)\\b|NO\\s+ACTION\\b)", "msg": "Column ON UPDATE expressions are CockroachDB-only", "fix": "a BEFORE UPDATE trigger"},
 {"id": "virtual-column", "sev": "error", "pattern": "\\)\\s*VIRTUAL\\b", "msg": "VIRTUAL computed columns are not in YSQL", "fix": "GENERATED ALWAYS AS (...) STORED, or a view"}
]
;</script>
<script>// YugabyteDB migration check: CockroachDB SQL that YSQL rejects or reads differently.
// Same file runs in node (VS Code) and in the browser (index.html).
(function () {
  var RULES = (typeof module !== 'undefined' && typeof require !== 'undefined') ? require('./rules.json') : window.YB_RULES;
  var LICENCE_DAY = Date.UTC(2024, 10, 18); // CockroachDB 24.3.0, new licence

  // Blank comments and string literals char-for-char, so offsets and line numbers survive
  // and a regex with \s+ can still span hard-wrapped statements.
  function blank(text) {
    var out = text.split(''), i = 0, n = text.length;
    function wipe(a, b) { for (var k = a; k < b; k++) if (out[k] !== '\n') out[k] = ' '; }
    while (i < n) {
      var c = text[i], d = text[i + 1];
      if (c === '-' && d === '-') { var e = text.indexOf('\n', i); if (e < 0) e = n; wipe(i, e); i = e; }
      else if (c === '/' && d === '*') { var f = text.indexOf('*/', i + 2); f = f < 0 ? n : f + 2; wipe(i, f); i = f; }
      else if (c === "'") {
        var j = i + 1;
        while (j < n) { if (text[j] === "'" && text[j + 1] === "'") j += 2; else if (text[j] === "'") break; else j++; }
        wipe(i + 1, j); i = j + 1;
      } else i++;
    }
    return out.join('');
  }

  function lineAt(text, idx) { var l = 1; for (var k = 0; k < idx; k++) if (text.charCodeAt(k) === 10) l++; return l; }

  function dayTail(today) {
    var m = String(today || '').match(/(\d{4})-(\d{2})-(\d{2})/);
    if (!m) return '';
    var t = Date.UTC(+m[1], +m[2] - 1, +m[3]);
    if (isNaN(t)) return '';
    var days = Math.round((t - LICENCE_DAY) / 86400000);
    return days >= 0 ? ' (' + m[0] + ' is ' + days + ' days after 2024-11-18)' : '';
  }

  function imageCovered(tag) {
    if (/^latest$/i.test(tag)) return true;
    var v = tag.replace(/^v/i, '').split('.');
    var major = +v[0], minor = +v[1];
    return major > 23 || (major === 23 && minor >= 1);
  }

  function check(text, opts) {
    text = String(text || '');
    opts = opts || {};
    var sql = blank(text), tail = dayTail(opts.today), findings = [];
    RULES.forEach(function (r) {
      var re = new RegExp(r.pattern, 'gi'), src = r.scope === 'image' ? text : sql, m;
      while ((m = re.exec(src)) !== null) {
        if (m[0] === '') { re.lastIndex++; continue; }
        var lead = m[0].search(/[^,(\s]/);
        var line = lineAt(src, m.index + (lead > 0 ? lead : 0));
        if (r.scope === 'image') {
          var raw = text.split('\n')[line - 1] || '';
          if (/^\s*(#|--)/.test(raw) || !imageCovered(m[1])) continue;
        }
        var msg = r.msg + (r.id.indexOf('licence') === 0 ? tail : '') + ' -> ' + r.fix;
        findings.push({ check: r.id, sev: r.sev, msg: msg, line: line, fix: r.fix });
      }
    });
    findings.sort(function (a, b) { return a.line - b.line; });
    return { findings: findings };
  }

  var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
  if (typeof module !== 'undefined' && module.exports) module.exports = API;
  if (typeof window !== 'undefined') window.YBENGINE = API;
})();
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
function summaryLine(res) {
  const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
  return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
  const f = (res && res.findings) || [];
  const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
  f.forEach(function (x) { lines.push('  ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + '  ' + (x.line ? 'L' + x.line + '  ' : '') + (x.check || x.id || '') + '  ' + (x.msg || x.message || '')); });
  return lines.join('\n');
}
function toHtml(res) {
  const f = (res && res.findings) || [];
  if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
  const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
  return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
}
var YBREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = YBREPORT;
else window.YBREPORT = YBREPORT;
</script>
<script>
(function(){
  var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
  today.value=new Date().toISOString().slice(0,10);
  function run(){ try { var res=window.YBENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.YBREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
  go.onclick=run; if (src.value.trim()) run();
})();
</script>


<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/yugabytedb-migration-check" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'yugabytedb-migration-check',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/team" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind YugabyteDB Migration Check: CockroachDB SQL every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"yugabytedb-migration-check",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);document.addEventListener("click",function(ev){var b=ev.target&&ev.target.closest?ev.target.closest("button,input[type=submit]"):null;if(b&&!b.closest("[data-yj],[data-yj-cta],[data-yj-install],[data-yj-alert],.yj-find,.yj-related,#yj-ask,.yjp"))mv(ev);},true);})();</script></section>

<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the full version <span class="yj-price">$29</span></h2><p class="yj-cta-paid" style="margin:.25rem 0 .6rem;color:#1f2a37">Scan every .sql migration in the workspace in one pass and export the findings as a Markdown migration report for the change ticket.</p><p class="yj-cta-pay" style="margin:.25rem 0 1rem;color:#5b6b7c;font-size:.94rem">One payment, one licence key for this tool. The key is shown right after payment.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_yhqnJUEktZxlbCzGL1oQIOykHs32vfHsmEH7j4B8RaP" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>

<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-30">Updated 2026-09-30</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-30","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku392238_result_card.jpg" alt="Migrate from CockroachDB to YugabyteDB: 6 findings in one orders.sql" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>6 findings in one CockroachDB orders.sql: that is what a YugabyteDB migration check returned for the schema a platform team exports first when it leaves self-hosted CockroachDB.</p>
<h3>What Cockroach Labs changed, and when</h3>
<p>Cockroach Labs retired the free CockroachDB Core edition with version 24.3.0 on 2024-11-18. Its Licensing FAQ says the CockroachDB Software License covers all versions from the 24.3.0 release date on, including patch fixes for 23.1 to 24.2 from that date. A cluster without a licence key gets a 7-day grace period, then is throttled to 5 concurrent open SQL transactions. Enterprise Free is for businesses with less than 10 million dollars in annual revenue, and Enterprise Free and Trial clusters are throttled after 7 days without sending telemetry. The Enterprise Trial lasts 30 days.</p>
<p>YugabyteDB is Apache-2.0 and speaks the PostgreSQL dialect, YSQL. CockroachDB also calls itself PostgreSQL-compatible, so the schema looks portable until the first <code>CREATE TABLE</code> runs.</p>
<h3>The file</h3>
<pre><code>SET CLUSTER SETTING diagnostics.reporting.enabled = false;

CREATE TABLE orders (
  id INT PRIMARY KEY DEFAULT unique_rowid(),
  customer_id UUID NOT NULL,
  status STRING NOT NULL DEFAULT &#x27;new&#x27;,
  total DECIMAL(12,2) NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  INDEX orders_customer_idx (customer_id)
);

UPSERT INTO orders (id, customer_id, status, total) VALUES (...);</code></pre>
<h3>The 6 findings</h3>
<ol><li><code>diagnostics.reporting.enabled = false</code> (licence-telemetry-off). On Enterprise Free this is the setting that gets a cluster throttled after 7 days. On YugabyteDB, delete it.</li><li><code>INT</code> (int-width). CockroachDB INT is 64-bit. YSQL INT is 32-bit, so ids above 2,147,483,647 overflow after the move. Write BIGINT.</li><li><code>unique_rowid()</code> (unique-rowid). A CockroachDB built-in with no YSQL equivalent. Use <code>BIGINT GENERATED BY DEFAULT AS IDENTITY</code>.</li><li><code>STRING</code> (string-type). A CockroachDB alias. Write TEXT.</li><li><code>INDEX orders_customer_idx (customer_id)</code> inside <code>CREATE TABLE</code> (inline-index). YSQL rejects it. Move it to <code>CREATE INDEX ... ON orders (customer_id)</code>.</li><li><code>UPSERT INTO</code> (upsert). Not in YSQL. Write <code>INSERT ... ON CONFLICT (id) DO UPDATE SET ...</code>.</li></ol>
<p>The rewritten file, with <code>PRIMARY KEY (id HASH)</code> and <code>INCLUDE (status)</code> on the index, returns 0 findings.</p>
<h3>Why a PostgreSQL linter does not catch it</h3>
<p>Finding 2 is the dangerous one. <code>INT</code> is perfectly valid PostgreSQL, so a generic linter passes it. It fails later, when an id crosses the 32-bit limit. Findings 3 to 6 fail loudly, but without the rewrite.</p>
<h3>What the 25 rules cover</h3>
<p>The extension groups its 25 rules into licence and settings (4), types and keys (5), DDL (10) and DML and operations (6). Beyond the six above it flags hash-sharded indexes with <code>bucket_count</code>, column families, <code>INVERTED INDEX</code> (use GIN), <code>STORING</code> (use INCLUDE), <code>CONFIGURE ZONE</code> and multi-region <code>LOCALITY</code> (use tablespaces with replica placement), <code>AS OF SYSTEM TIME</code>, <code>CREATE CHANGEFEED</code>, <code>crdb_internal</code> and <code>BACKUP</code>/<code>RESTORE</code>.</p>
<h3>Try it on your own file</h3>
<p>Open any <code>.sql</code> file in VS Code and the findings land in the Problems panel, each ending with the YSQL rewrite. The same engine runs on the web page at getreadystack.com/tools/yugabytedb-migration-check, in the browser, with nothing uploaded. Checking one file is free and complete. The full version scans every migration in the workspace at once and exports a Markdown report for the change ticket.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku392238_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku392238_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does YugabyteDB Migration Check do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a CockroachDB .sql schema or migration file and marks every line YugabyteDB YSQL rejects or reads differently, with the rewrite. It has 25 rules and 2 inputs: the .sql file text and today&#x27;s date. On the sample orders.sql it returns 6 findings, including UPSERT INTO, unique_rowid(), STRING and 64-bit INT; the rewritten file returns 0.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this migration check for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Platform, backend and database engineers who self-host CockroachDB and are moving to YugabyteDB after CockroachDB 24.3.0 (2024-11-18) retired the free Core edition. It fits companies above the $10M annual revenue limit of Enterprise Free, and teams whose clusters would be throttled to 5 concurrent open SQL transactions without a licence key.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not use a free PostgreSQL linter to check CockroachDB SQL?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A PostgreSQL linter accepts INT as valid SQL, but CockroachDB INT is 64-bit and YugabyteDB YSQL INT is 32-bit, so values above 2,147,483,647 overflow after the move without any warning. CockroachDB extensions like STRING, UPSERT INTO, unique_rowid(), STORING and inline INDEX are also not in a PostgreSQL rule set.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what does the full version add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free: check one CockroachDB .sql file, completely, with all 25 rules in 4 groups: licence and settings (4), types and keys (5), DDL (10), DML and operations (6). No key is needed. Full version, $29 once with one licence key per person or team seat: scan every .sql migration in the workspace in one pass and export a Markdown migration report.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does staying on CockroachDB self-hosted cost instead?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Under the CockroachDB Software License, businesses at or above $10M annual revenue need a paid Enterprise licence, priced per vCPU. A cluster without a key gets a 7-day grace and is then throttled to 5 concurrent open SQL transactions. Enterprise Free clusters are also throttled after 7 days without telemetry. YugabyteDB is Apache-2.0.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does YugabyteDB Migration Check do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a CockroachDB .sql schema or migration file and marks every line YugabyteDB YSQL rejects or reads differently, with the rewrite. It has 25 rules and 2 inputs: the .sql file text and today's date. On the sample orders.sql it returns 6 findings, including UPSERT INTO, unique_rowid(), STRING and 64-bit INT; the rewritten file returns 0."}}, {"@type": "Question", "name": "Who is this migration check for?", "acceptedAnswer": {"@type": "Answer", "text": "Platform, backend and database engineers who self-host CockroachDB and are moving to YugabyteDB after CockroachDB 24.3.0 (2024-11-18) retired the free Core edition. It fits companies above the $10M annual revenue limit of Enterprise Free, and teams whose clusters would be throttled to 5 concurrent open SQL transactions without a licence key."}}, {"@type": "Question", "name": "Why not use a free PostgreSQL linter to check CockroachDB SQL?", "acceptedAnswer": {"@type": "Answer", "text": "A PostgreSQL linter accepts INT as valid SQL, but CockroachDB INT is 64-bit and YugabyteDB YSQL INT is 32-bit, so values above 2,147,483,647 overflow after the move without any warning. CockroachDB extensions like STRING, UPSERT INTO, unique_rowid(), STORING and inline INDEX are also not in a PostgreSQL rule set."}}, {"@type": "Question", "name": "What is free and what does the full version add?", "acceptedAnswer": {"@type": "Answer", "text": "Free: check one CockroachDB .sql file, completely, with all 25 rules in 4 groups: licence and settings (4), types and keys (5), DDL (10), DML and operations (6). No key is needed. Full version, $29 once with one licence key per person or team seat: scan every .sql migration in the workspace in one pass and export a Markdown migration report."}}, {"@type": "Question", "name": "What does staying on CockroachDB self-hosted cost instead?", "acceptedAnswer": {"@type": "Answer", "text": "Under the CockroachDB Software License, businesses at or above $10M annual revenue need a paid Enterprise licence, priced per vCPU. A cluster without a key gets a 7-day grace and is then throttled to 5 concurrent open SQL transactions. Enterprise Free clusters are also throttled after 7 days without telemetry. YugabyteDB is Apache-2.0."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:392238,slug:"yugabytedb-migration-check",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/cinc-migration-check"><span class="yj-rel-t">Cinc Migration Check: Chef Infra licence gate lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/js-licence-key-gate"><span class="yj-rel-t">JS Licence Key Gate: GPL &amp; Eval Keys</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pekko-migration-gate"><span class="yj-rel-t">Pekko Migration Gate — Akka BSL licence check</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pyside6-migration-lint"><span class="yj-rel-t">PySide6 Migration Lint: PyQt5/PyQt6 Licence Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/mssql-container-licence-lint"><span class="yj-rel-t">SQL Server Docker Licence Lint (MSSQL_PID)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/vscodium-extension-licence-lint"><span class="yj-rel-t">VSCodium Migration Lint: Microsoft-only Extensions</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
</html>