Download index.html from getreadystack/yugabytedb-migration-check: direct link, hf CLI and curl.
- Browser
- Download file 43.2 kB
-
https://huggingface.co/spaces/getreadystack/yugabytedb-migration-check/resolve/main/index.html
- Command line
-
hf download hf://spaces/getreadystack/yugabytedb-migration-check/index.html
-
curl -L -o index.html https://huggingface.co/spaces/getreadystack/yugabytedb-migration-check/resolve/main/index.html
43.2 kB
| <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;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 와 브라우저에서 산다. | |
| ; | |
| function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); } | |
| 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 {"&":"&","<":"<",">":">",'"':"""}[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 '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 (...);</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'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 & 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> | |