Guides

NJ Cannabis Profit Margin & 280E Calculator Guide

CCA Staff·September 10, 2026
NJ Cannabis Profit Margin & 280E Calculator Guide

<div class="njc-wrap" aria-label="NJ Cannabis Profit Margin & 280E Impact Calculator">
<div class="njc-card">
<div class="njc-head">
<h2 class="njc-title">NJ Cannabis Profit Margin &amp; 280E Impact Calculator</h2>
<p class="njc-subtitle">Estimate gross margin, operating margin, and after-tax profit under normal tax treatment vs. when <strong>IRC 280E</strong> applies. Enter your numbers, click calculate, and review the comparison below.</p>
</div>

<div class="njc-infobox" role="note" aria-label="Important context">
<div class="njc-infobox-title">How this works (simple estimate)</div>
<ul class="njc-infobox-list">
<li><strong>Normal tax treatment:</strong> taxable income  revenue  COGS  operating expenses.</li>
<li><strong>280E applies:</strong> operating expenses are not deductible; taxable income is estimated as <u>revenue  COGS</u>.</li>
<li>This is a planning tool, not tax advice. NJ specifics can vary by license type, accounting method, and what qualifies as COGS.</li>
</ul>
</div>

<form class="njc-form" aria-label="Calculator form">
<div class="njc-group">
<label class="njc-label" for="njc-period">Input period</label>
<select class="njc-select" id="njc-period" aria-label="Input period">
<option value="monthly">Monthly</option>
<option value="annual">Annual</option>
</select>
<div class="njc-help">Tip: If you enter monthly figures, results will also show an annualized view.</div>
</div>

<div class="njc-group">
<label class="njc-label" for="njc-revenue">Revenue ($)</label>
<input class="njc-input" id="njc-revenue" type="text" inputmode="decimal" placeholder="e.g., 250000" aria-label="Revenue in dollars" />
</div>

<div class="njc-group">
<label class="njc-label" for="njc-cogs">COGS  cost of goods sold ($)</label>
<input class="njc-input" id="njc-cogs" type="text" inputmode="decimal" placeholder="e.g., 120000" aria-label="COGS in dollars" />

<label class="njc-check">
<input id="njc-cogs-breakdown-toggle" type="checkbox" aria-label="Show optional COGS breakdown" />
<span>Show optional COGS breakdown</span>
</label>

<div class="njc-subpanel" id="njc-cogs-breakdown" hidden aria-label="COGS breakdown fields">
<div class="njc-help">Optional: these do not change the math unless you leave total COGS blank (then breakdown will be summed).</div>
<label class="njc-label" for="njc-cogs-inventory">Inventory / wholesale purchases ($)</label>
<input class="njc-input" id="njc-cogs-inventory" type="text" inputmode="decimal" placeholder="e.g., 70000" aria-label="Inventory or purchases COGS" />

<label class="njc-label" for="njc-cogs-directlab">Direct labor / production ($)</label>
<input class="njc-input" id="njc-cogs-directlab" type="text" inputmode="decimal" placeholder="e.g., 30000" aria-label="Direct labor COGS" />

<label class="njc-label" for="njc-cogs-other">Other COGS ($)</label>
<input class="njc-input" id="njc-cogs-other" type="text" inputmode="decimal" placeholder="e.g., 20000" aria-label="Other COGS" />
</div>
</div>

<div class="njc-group">
<label class="njc-label" for="njc-opex">Operating expenses (non-COGS) ($)</label>
<input class="njc-input" id="njc-opex" type="text" inputmode="decimal" placeholder="e.g., 90000" aria-label="Operating expenses in dollars" />
<div class="njc-help">Examples: payroll (non-direct), rent, marketing, admin, insurance, compliance, professional fees.</div>
</div>

<div class="njc-group">
<label class="njc-label" for="njc-entity">Entity type (for context)</label>
<select class="njc-select" id="njc-entity" aria-label="Entity type">
<option value="ccorp">C-Corp</option>
<option value="passthrough">Pass-through (LLC / S-Corp / Sole prop)</option>
</select>
<div class="njc-help">Entity type can change your effective tax rate. Use your best estimate below.</div>
</div>

<div class="njc-group">
<label class="njc-label" for="njc-taxrate">Estimated combined effective tax rate (%)</label>
<input class="njc-input" id="njc-taxrate" type="text" inputmode="decimal" placeholder="e.g., 30" aria-label="Combined effective tax rate percent" value="30" />
<div class="njc-help">Enter a single blended rate (federal + NJ + other). If unsure, start with 2535% and refine.</div>
</div>

<div class="njc-group">
<label class="njc-label" for="njc-scenario">Tax scenario to display</label>
<select class="njc-select" id="njc-scenario" aria-label="Tax scenario">
<option value="compare">Compare: Normal vs 280E</option>
<option value="normal">Normal tax treatment only</option>
<option value="280e">280E applies only</option>
</select>
</div>

<button class="njc-btn" type="submit" aria-label="Calculate profit margins and 280E impact">Calculate</button>

<div class="njc-error" id="njc-error" role="alert" aria-label="Form error" hidden></div>
</form>

<div class="njc-leadGate" id="njc-leadGate" hidden aria-label="Lead details">
<div class="njc-leadBox">
<div class="njc-leadHeading">Your results are ready</div>
<div class="njc-leadDesc">Enter your business details to view the full profit margin and 280E comparison.</div>

<div class="njc-group">
<label class="njc-label" for="njc-lead-company">Company name</label>
<input class="njc-input" id="njc-lead-company" type="text" placeholder="e.g., Garden State Cannabis LLC" />
</div>

<div class="njc-group">
<label class="njc-label" for="njc-lead-email">Business email</label>
<input class="njc-input" id="njc-lead-email" type="email" placeholder="you@company.com" />
<div class="njc-leadEmailErr" id="njc-leadEmailErr" hidden>Please enter a valid business email.</div>
</div>

<div class="njc-group">
<label class="njc-label" for="njc-lead-role">Which best describes you?</label>
<select class="njc-select" id="njc-lead-role">
<option value="">— Select —</option>
<option value="dispensary_retailer">Dispensary / Retailer</option>
<option value="cultivator_processor">Cultivator / Processor</option>
<option value="distributor">Distributor</option>
<option value="brand_manufacturer">Brand / Manufacturer</option>
<option value="consultant_advisor">Consultant / Advisor</option>
<option value="other">Other</option>
</select>
</div>

<button class="njc-btn" type="button" id="njc-show-results">Show My Results</button>
<div class="njc-leadError" id="njc-leadError" hidden></div>
<div class="njc-leadTrust">CannaBiz Credit Association · Cannabis credit reports &amp; risk monitoring · 30+ state markets</div>
</div>
</div>

<div class="njc-results" id="njc-results" hidden aria-label="Results section">
<div class="njc-results-head">
<h3 class="njc-results-title">Results</h3>
<p class="njc-results-sub" id="njc-results-sub"></p>
</div>

<div class="njc-sep" aria-hidden="true"></div>

<div id="njc-results-body"></div>

<div class="njc-note" aria-label="Disclaimer">
<strong>Note:</strong> This calculator treats 280E as disallowing <em>all</em> operating expense deductions and allowing only COGS. Actual outcomes depend on your accounting method, what is properly capitalizable to inventory, state conformity, and your specific facts.
</div>
</div>
</div>
</div>

<style>
.njc-wrap{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#111;}
.njc-card{max-width:760px;margin:0 auto;background:#fff;border-radius:12px;padding:40px;box-shadow:0 10px 30px rgba(0,0,0,.08);border:1px solid rgba(17,17,17,.06);}
.njc-head{text-align:center;margin-bottom:22px;}
.njc-title{font-size:32px;line-height:1.15;margin:0 0 10px;font-weight:800;letter-spacing:-0.02em;}
.njc-subtitle{font-size:16px;line-height:1.5;margin:0;color:rgba(17,17,17,.70);}

.njc-infobox{margin:22px 0 26px;padding:14px 16px;border-left:4px solid #1f7a4d;background:rgba(31,122,77,.06);border-radius:10px;}
.njc-infobox-title{font-weight:700;margin-bottom:6px;}
.njc-infobox-list{margin:0;padding-left:18px;color:rgba(17,17,17,.78);}
.njc-infobox-list li{margin:6px 0;}

.njc-form{margin-top:10px;}
.njc-group{margin:16px 0;}
.njc-label{display:block;font-weight:700;margin:0 0 8px;}
.njc-input,.njc-select{width:100%;padding:12px 12px;border-radius:10px;border:1px solid rgba(17,17,17,.18);background:#fff;font-size:16px;outline:none;}
.njc-input:focus,.njc-select:focus{border-color:rgba(31,122,77,.55);box-shadow:0 0 0 4px rgba(31,122,77,.12);}
.njc-help{margin-top:8px;font-size:13px;line-height:1.45;color:rgba(17,17,17,.65);}

.njc-check{display:flex;gap:10px;align-items:flex-start;margin-top:10px;font-size:14px;color:rgba(17,17,17,.78);}
.njc-check input{margin-top:3px;}

.njc-subpanel{margin-top:12px;padding:12px;border:1px solid rgba(17,17,17,.12);border-radius:10px;background:rgba(0,0,0,.02);}

.njc-btn{width:100%;margin-top:10px;background:#1f7a4d;color:#fff;border:0;border-radius:12px;padding:14px 16px;font-size:16px;font-weight:800;cursor:pointer;}
.njc-btn:hover{filter:brightness(0.98);}
.njc-btn:active{transform:translateY(1px);}

.njc-error{margin-top:12px;padding:12px 14px;border-radius:10px;border:1px solid rgba(176,0,32,.25);background:rgba(176,0,32,.06);color:#6b0015;}

.njc-results{margin-top:26px;}
.njc-results-head{text-align:left;}
.njc-results-title{font-size:22px;margin:0 0 6px;font-weight:800;}
.njc-results-sub{margin:0;color:rgba(17,17,17,.68);font-size:14px;line-height:1.45;}
.njc-sep{margin:16px 0;border-top:1px solid rgba(17,17,17,.12);}

.njc-table{width:100%;border-collapse:collapse;border:1px solid rgba(17,17,17,.12);border-radius:12px;overflow:hidden;}
.njc-table th,.njc-table td{padding:12px 12px;border-bottom:1px solid rgba(17,17,17,.10);vertical-align:top;}
.njc-table th{background:rgba(31,122,77,.06);text-align:left;font-size:13px;letter-spacing:.02em;text-transform:uppercase;color:rgba(17,17,17,.70);}
.njc-table td{font-size:14px;}
.njc-table tr:last-child td{border-bottom:0;}

.njc-metric{display:flex;justify-content:space-between;gap:14px;}
.njc-metric .njc-k{color:rgba(17,17,17,.72);}
.njc-metric .njc-v{font-weight:800;}

.njc-badge{display:inline-block;padding:4px 8px;border-radius:999px;font-size:12px;font-weight:800;}
.njc-badge-good{background:rgba(31,122,77,.10);color:#1f7a4d;}
.njc-badge-warn{background:rgba(179,92,0,.10);color:#8a4a00;}

.njc-note{margin-top:14px;padding:12px 14px;border-radius:10px;border:1px solid rgba(17,17,17,.10);background:rgba(0,0,0,.02);color:rgba(17,17,17,.72);font-size:13px;line-height:1.5;}

.njc-leadGate{margin-top:26px;}
.njc-leadBox{border:2px solid rgba(31,122,77,.22);border-radius:14px;background:linear-gradient(135deg,rgba(31,122,77,.06),#fff);padding:24px;}
.njc-leadHeading{font-size:18px;font-weight:800;color:#1f7a4d;margin-bottom:6px;}
.njc-leadDesc{font-size:14px;line-height:1.5;color:rgba(17,17,17,.68);margin-bottom:16px;}
.njc-leadEmailErr,.njc-leadError{margin-top:8px;color:#991b1b;font-size:13px;}
.njc-leadError{padding:10px 12px;border:1px solid rgba(176,0,32,.22);background:rgba(176,0,32,.05);border-radius:10px;}
.njc-leadTrust{font-size:11px;color:rgba(17,17,17,.45);text-align:center;margin-top:14px;}

@media (max-width:640px){
.njc-card{padding:22px;}
.njc-title{font-size:26px;}
}
</style>

<script>
(function(){
var el = function(id){ return document.getElementById(id); };

var form = document.querySelector('.njc-form');
var results = el('njc-results');
var resultsBody = el('njc-results-body');
var resultsSub = el('njc-results-sub');
var errorBox = el('njc-error');

var LEAD_CONFIG = {
API_URL: 'https://cannabiz-leads.vercel.app/api/lead',
SHARED_SECRET: 'cannabiz_lead_2025_Xk9mP7nQ2vR8wL4jT6hY3sF9dA1bC5eG0iN',
DOMAIN_LABEL: 'cannabizcredit.com',
PAGE_ID: 'nj-cannabis-profit-margin-280e-calculator'
};

var leadGate = el('njc-leadGate');
var leadCompanyEl = el('njc-lead-company');
var leadEmailEl = el('njc-lead-email');
var leadRoleEl = el('njc-lead-role');
var leadEmailErr = el('njc-leadEmailErr');
var leadError = el('njc-leadError');
var showResultsBtn = el('njc-show-results');

var pendingResult = null;
var leadSubmitted = false;
var emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

var periodEl = el('njc-period');
var revenueEl = el('njc-revenue');
var cogsEl = el('njc-cogs');
var opexEl = el('njc-opex');
var entityEl = el('njc-entity');
var taxRateEl = el('njc-taxrate');
var scenarioEl = el('njc-scenario');

var breakdownToggle = el('njc-cogs-breakdown-toggle');
var breakdownPanel = el('njc-cogs-breakdown');
var cogsInvEl = el('njc-cogs-inventory');
var cogsLabEl = el('njc-cogs-directlab');
var cogsOtherEl = el('njc-cogs-other');

breakdownToggle.addEventListener('change', function(){
breakdownPanel.hidden = !breakdownToggle.checked;
});

function parseMoney(v){
if(v == null) return NaN;
var s = String(v).trim();
if(!s) return NaN;
// allow $ and commas and parentheses
var neg = false;
if(s.indexOf('(') !== -1 && s.indexOf(')') !== -1){ neg = true; }
s = s.replace(/[^0-9.\-]/g,'');
var n = parseFloat(s);
if(!isFinite(n)) return NaN;
if(neg) n = -Math.abs(n);
return n;
}

function parsePercent(v){
if(v == null) return NaN;
var s = String(v).trim();
if(!s) return NaN;
s = s.replace(/%/g,'').replace(/,/g,'');
var n = parseFloat(s);
if(!isFinite(n)) return NaN;
return n / 100;
}

var usd0 = new Intl.NumberFormat(undefined,{style:'currency',currency:'USD',maximumFractionDigits:0});
var usd2 = new Intl.NumberFormat(undefined,{style:'currency',currency:'USD',maximumFractionDigits:2});

function fmtMoney(n){
if(!isFinite(n)) return '—';
var abs = Math.abs(n);
if(abs >= 1000) return usd0.format(n);
return usd2.format(n);
}

function fmtPct(n){
if(!isFinite(n)) return '—';
return (n*100).toFixed(1) + '%';
}

function clampMinZero(n){ return n > 0 ? n : 0; }

function badgeHtml(label, kind){
var cls = kind === 'warn' ? 'njc-badge njc-badge-warn' : 'njc-badge njc-badge-good';
return '<span class="' + cls + '">' + label + '</span>';
}

function buildScenario(name, rev, cogs, opex, taxRate, mode){
var grossProfit = rev - cogs;
var operatingProfit = rev - cogs - opex;
var taxable = (mode === '280e') ? grossProfit : operatingProfit;
var tax = clampMinZero(taxable) * taxRate;
var afterTax = operatingProfit - tax;

var grossMargin = rev !== 0 ? (grossProfit / rev) : NaN;
var operatingMargin = rev !== 0 ? (operatingProfit / rev) : NaN;
var afterTaxMargin = rev !== 0 ? (afterTax / rev) : NaN;

return {
name: name,
mode: mode,
revenue: rev,
cogs: cogs,
opex: opex,
grossProfit: grossProfit,
operatingProfit: operatingProfit,
taxableIncome: taxable,
tax: tax,
afterTax: afterTax,
grossMargin: grossMargin,
operatingMargin: operatingMargin,
afterTaxMargin: afterTaxMargin
};
}

function renderScenarioTable(rows){
var html = '';
html += '<table class="njc-table" aria-label="Scenario results table">';
html += '<thead><tr>';
html += '<th>Scenario</th>';
html += '<th>Margins</th>';
html += '<th>Profit &amp; Tax (estimate)</th>';
html += '</tr></thead>';
html += '<tbody>';

rows.forEach(function(r){
var flag = '';
if(r.mode === '280e') flag = badgeHtml('280E', 'warn');
else flag = badgeHtml('Normal', 'good');

html += '<tr>';
html += '<td>';
html += '<div style="font-weight:800; margin-bottom:6px;">' + r.name + ' ' + flag + '</div>';
html += '<div class="njc-metric"><span class="njc-k">Revenue</span><span class="njc-v">' + fmtMoney(r.revenue) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">COGS</span><span class="njc-v">' + fmtMoney(r.cogs) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">OpEx</span><span class="njc-v">' + fmtMoney(r.opex) + '</span></div>';
html += '</td>';

html += '<td>';
html += '<div class="njc-metric"><span class="njc-k">Gross margin</span><span class="njc-v">' + fmtPct(r.grossMargin) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">Operating margin</span><span class="njc-v">' + fmtPct(r.operatingMargin) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">After-tax margin</span><span class="njc-v">' + fmtPct(r.afterTaxMargin) + '</span></div>';
html += '</td>';

html += '<td>';
html += '<div class="njc-metric"><span class="njc-k">Gross profit</span><span class="njc-v">' + fmtMoney(r.grossProfit) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">Operating profit</span><span class="njc-v">' + fmtMoney(r.operatingProfit) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">Taxable income</span><span class="njc-v">' + fmtMoney(r.taxableIncome) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">Estimated tax</span><span class="njc-v">' + fmtMoney(r.tax) + '</span></div>';
html += '<div class="njc-metric"><span class="njc-k">After-tax profit</span><span class="njc-v">' + fmtMoney(r.afterTax) + '</span></div>';
html += '</td>';
html += '</tr>';
});

html += '</tbody></table>';
return html;
}

function showError(msg){
errorBox.textContent = msg;
errorBox.hidden = false;
}
function clearError(){
errorBox.hidden = true;
errorBox.textContent = '';
}

function validateLead(){
var company = String(leadCompanyEl.value || '').trim();
var email = String(leadEmailEl.value || '').trim();
var role = leadRoleEl.value || '';
var okEmail = emailRe.test(email);
leadEmailErr.hidden = okEmail || !email;
if(!company || !okEmail || !role){
leadError.textContent = 'Please fill in all fields with a valid business email.';
leadError.hidden = false;
return false;
}
leadError.hidden = true;
return true;
}

function submitLead(context){
if(leadSubmitted) return;
leadSubmitted = true;

var payload = {
company: String(leadCompanyEl.value || '').trim(),
email: String(leadEmailEl.value || '').trim(),
role: leadRoleEl.value || '',
domain: LEAD_CONFIG.DOMAIN_LABEL,
page: LEAD_CONFIG.PAGE_ID,
context: context || {},
utm: {}
};

try {
var sp = new URLSearchParams(window.location.search || '');
['utm_source','utm_medium','utm_campaign','utm_term','utm_content'].forEach(function(k){
if(sp.get(k)) payload.utm[k] = sp.get(k);
});
} catch(e){}

(async function(){
try {
var ctrl = (typeof AbortSignal !== 'undefined' && AbortSignal.timeout) ? AbortSignal.timeout(2000) : undefined;
var ipRes = await fetch('https://api.ipify.org?format=json', {signal: ctrl});
var ipData = await ipRes.json();
payload.ip = ipData.ip;
} catch(e){}

try {
await fetch(LEAD_CONFIG.API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-shared-secret': LEAD_CONFIG.SHARED_SECRET
},
body: JSON.stringify(payload)
});
} catch(e){}
})();
}

function revealPendingResult(){
if(!pendingResult) return;
resultsSub.textContent = pendingResult.sub;
resultsBody.innerHTML = pendingResult.html;
results.hidden = false;
leadGate.hidden = true;
results.scrollIntoView({behavior:'smooth', block:'start'});
}

leadEmailEl.addEventListener('input', function(){
var email = String(leadEmailEl.value || '').trim();
leadEmailErr.hidden = emailRe.test(email) || !email;
});

showResultsBtn.addEventListener('click', function(){
if(!validateLead()) return;
submitLead(pendingResult ? pendingResult.context : {});
revealPendingResult();
});

form.addEventListener('submit', function(e){
e.preventDefault();
clearError();

var period = periodEl.value;
var rev = parseMoney(revenueEl.value);
var cogs = parseMoney(cogsEl.value);
var opex = parseMoney(opexEl.value);
var taxRate = parsePercent(taxRateEl.value);
var scenario = scenarioEl.value;

// If total COGS not provided, but breakdown is used, sum it.
if(!isFinite(cogs) && breakdownToggle.checked){
var b1 = parseMoney(cogsInvEl.value); if(!isFinite(b1)) b1 = 0;
var b2 = parseMoney(cogsLabEl.value); if(!isFinite(b2)) b2 = 0;
var b3 = parseMoney(cogsOtherEl.value); if(!isFinite(b3)) b3 = 0;
var sum = b1 + b2 + b3;
if(sum > 0) cogs = sum;
}

if(!isFinite(rev) || rev <= 0){
showError('Please enter a revenue amount greater than 0.');
results.hidden = true;
leadGate.hidden = true;
return;
}
if(!isFinite(cogs) || cogs < 0){
showError('Please enter a valid COGS amount (0 or more).');
results.hidden = true;
leadGate.hidden = true;
return;
}
if(!isFinite(opex) || opex < 0){
showError('Please enter a valid operating expense amount (0 or more).');
results.hidden = true;
leadGate.hidden = true;
return;
}
if(!isFinite(taxRate) || taxRate < 0 || taxRate > 0.7){
showError('Please enter a reasonable combined effective tax rate (for example, 25 to 40).');
results.hidden = true;
leadGate.hidden = true;
return;
}

var normal = buildScenario('Normal tax treatment', rev, cogs, opex, taxRate, 'normal');
var e280 = buildScenario('280E applies', rev, cogs, opex, taxRate, '280e');

var rows = [];
if(scenario === 'compare') rows = [normal, e280];
if(scenario === 'normal') rows = [normal];
if(scenario === '280e') rows = [e280];

var penaltyHtml = '';
if(scenario === 'compare'){
var taxPenalty = e280.tax - normal.tax;
var profitHit = e280.afterTax - normal.afterTax; // usually negative
penaltyHtml += '<div class="njc-note" aria-label="280E delta summary">'
+ '<div style="font-weight:800; margin-bottom:6px;">280E impact (difference vs. normal)</div>'
+ '<div class="njc-metric"><span class="njc-k">Additional estimated tax</span><span class="njc-v">' + fmtMoney(taxPenalty) + '</span></div>'
+ '<div class="njc-metric"><span class="njc-k">After-tax profit change</span><span class="njc-v">' + fmtMoney(profitHit) + '</span></div>'
+ '<div class="njc-help" style="margin-top:8px;">Under 280E, taxes can be due even when operating profit is low (or negative), because taxable income is based on gross profit.</div>'
+ '</div>';
}

var entityTxt = (entityEl.value === 'ccorp') ? 'C-Corp' : 'Pass-through';
var taxRateTxt = (taxRate*100).toFixed(1) + '%';

var sub = 'Period: ' + (period === 'monthly' ? 'Monthly' : 'Annual') + '  Entity: ' + entityTxt + '  Effective tax rate used: ' + taxRateTxt + '.';

var annualBlock = '';
if(period === 'monthly'){
var arev = rev * 12;
var acogs = cogs * 12;
var aopex = opex * 12;
var an = buildScenario('Normal tax treatment (annualized)', arev, acogs, aopex, taxRate, 'normal');
var a2 = buildScenario('280E applies (annualized)', arev, acogs, aopex, taxRate, '280e');

annualBlock += '<div class="njc-sep" aria-hidden="true"></div>';
annualBlock += '<h4 style="margin:0 0 10px; font-size:16px; font-weight:800;">Annualized view (monthly  12)</h4>';
if(scenario === 'compare') annualBlock += renderScenarioTable([an, a2]);
if(scenario === 'normal') annualBlock += renderScenarioTable([an]);
if(scenario === '280e') annualBlock += renderScenarioTable([a2]);
}

// Optional breakdown note
var breakdownNote = '';
if(breakdownToggle.checked){
var b1n = parseMoney(cogsInvEl.value); if(!isFinite(b1n)) b1n = 0;
var b2n = parseMoney(cogsLabEl.value); if(!isFinite(b2n)) b2n = 0;
var b3n = parseMoney(cogsOtherEl.value); if(!isFinite(b3n)) b3n = 0;
var sumN = b1n + b2n + b3n;
if(sumN > 0){
var delta = (isFinite(cogs) ? (cogs - sumN) : 0);
var mismatch = Math.abs(delta) > 1;
breakdownNote += '<div class="njc-note" aria-label="COGS breakdown summary">'
+ '<div style="font-weight:800; margin-bottom:6px;">COGS breakdown (optional)</div>'
+ '<div class="njc-metric"><span class="njc-k">Inventory / purchases</span><span class="njc-v">' + fmtMoney(b1n) + '</span></div>'
+ '<div class="njc-metric"><span class="njc-k">Direct labor</span><span class="njc-v">' + fmtMoney(b2n) + '</span></div>'
+ '<div class="njc-metric"><span class="njc-k">Other COGS</span><span class="njc-v">' + fmtMoney(b3n) + '</span></div>'
+ '<div class="njc-metric"><span class="njc-k">Breakdown total</span><span class="njc-v">' + fmtMoney(sumN) + '</span></div>'
+ (mismatch ? '<div class="njc-help" style="margin-top:8px;">Note: Your total COGS input (' + fmtMoney(cogs) + ') does not match the breakdown total. The calculator uses the total COGS field.</div>' : '')
+ '</div>';
}
}

var resultHtml = renderScenarioTable(rows) + penaltyHtml + breakdownNote + annualBlock;

pendingResult = {
sub: sub,
html: resultHtml,
context: {
tool: 'nj-cannabis-profit-margin-280e-calculator',
period: period,
revenue: rev,
cogs: cogs,
operating_expenses: opex,
entity_type: entityEl.value,
effective_tax_rate: (taxRate * 100).toFixed(1),
scenario: scenario,
normal_taxable_income: normal.taxableIncome,
normal_estimated_tax: normal.tax,
normal_after_tax_profit: normal.afterTax,
normal_after_tax_margin: normal.afterTaxMargin,
e280_taxable_income: e280.taxableIncome,
e280_estimated_tax: e280.tax,
e280_after_tax_profit: e280.afterTax,
e280_after_tax_margin: e280.afterTaxMargin,
additional_estimated_tax_280e: e280.tax - normal.tax,
after_tax_profit_change_280e: e280.afterTax - normal.afterTax
}
};

results.hidden = true;

if(leadSubmitted){
revealPendingResult();
} else {
leadGate.hidden = false;
leadGate.scrollIntoView({behavior:'smooth', block:'start'});
}
});
})();
</script>

New Jersey dispensary margins can look strong—until federal taxes turn “profit” into a cash squeeze. That’s why an NJ Cannabis Profit Margin & 280E Calculator is essential: it helps you see profitability before 280E distortions and the real cash margin after the 280E hit, using numbers you can manage week to week.

Below is a practical, step-by-step guide to building a calculator that matches how cannabis businesses are actually taxed, plus benchmarks and levers you can use to improve results—grounded in real industry data from cannabis accounting firms and CFO benchmarking resources.

Why NJ cannabis profitability is tricky: 280E taxes your gross profit, not your net

In most industries, you pay income tax on net income (revenue minus all ordinary expenses). Cannabis is different. As explained by CannaBIZ Collects, IRC Section 280E prohibits cannabis businesses from deducting ordinary business expenses, which means many operators are effectively taxed on gross profit rather than true net income. The result can be punishing effective tax rates—CannaBIZ Collects notes effective rates can exceed 70% in some cases.

What that means in practice (and why “net margin” can mislead)

TheCannaCPAs highlights that traditional metrics like net profit margin or EBITDA can become “meaningless” if you don’t account for 280E. They recommend tracking both:

  • Pre-280E gross margin to measure core operational efficiency
  • Post-280E effective margin to measure true cash profitability after taxes

This is the core idea behind a solid NJ Cannabis Profit Margin & 280E Calculator: you’re not just calculating accounting profit—you’re modeling the tax reality that drives cash flow.

NJ-specific context: strong pricing power, but 280E can still overwhelm cash flow

Northstar Financial Advisory notes that in limited-license states like New Jersey, dispensaries often maintain stronger margins “across every layer of the P&L.” They cite gross margins of 52% to 60% as common due to pricing power, and EBITDA margins of 15% to 25% as achievable for well-run operations.

However, TCA Advisors (focused on NJ dispensary accounting) warns that adult-use dispensaries still pay federal tax on gross profit, with effective rates from 40% to over 100% depending on margin structure. In other words: NJ operators may have stronger top-line economics, but the wrong cost structure and weak 280E planning can still crush after-tax cash.

The key formulas your NJ Cannabis Profit Margin & 280E Calculator must include

To make decisions you can trust, your calculator should separate “business performance” from “tax distortion.” TheCannaCPAs lays out the core framework.

1) Pre-280E gross margin (your baseline operational efficiency)

Gross Margin = (Revenue − COGS) ÷ Revenue

This shows how efficiently you produce or procure inventory before tax distortions. CannaBIZ Collects describes gross margin as the core operational profitability metric and notes that for cannabis retail, a healthy gross margin typically ranges from 50% to 60%, though it varies by market and regulation.

2) Post-280E effective margin (your real cash margin after tax)

TheCannaCPAs recommends calculating a “post-280E effective margin” by adjusting for estimated tax liability:

Post-280E Effective Margin = (Gross Profit − Estimated Tax Liability) ÷ Revenue

This is the number that tells you whether your model is sustainable—because it reflects the cash impact of being taxed on gross profit.

3) Effective tax rate (the KPI that explains the pain)

TheCannaCPAs provides a simple KPI to quantify the 280E burden:

Effective Tax Rate = (Total Tax Liability ÷ Gross Profit) × 100

They note cannabis businesses often see effective tax rates of 40% to 70%, compared to 15% to 25% for traditional businesses. CannaBIZ Collects adds that effective rates can exceed 70% in some cases, and NJ-focused guidance (TCA Advisors) notes scenarios from 40% to over 100% depending on structure.

4) Cash flow and working capital (because tax bills don’t wait)

Even if your P&L looks profitable, the timing of taxes, inventory purchases, and payables can break you. TheCannaCPAs emphasizes tracking cash flow from operations quarterly to spot seasonal patterns and cash needs, including changes in inventory, receivables, and payables.

They also note cannabis businesses often need 3–6 months of operating expenses in working capital due to banking limitations and inventory requirements—an important planning assumption to incorporate when your effective tax rate is high.

How to build an NJ 280E calculator (step-by-step) that mirrors reality

You don’t need complex software to start. You need the right inputs and a consistent method. Here’s a simple workflow you can implement in a spreadsheet.

Step 1: Collect the minimum inputs

  • Total revenue (monthly or quarterly)
  • COGS (the costs treated as inventory costs)
  • Operating expenses (rent, payroll, marketing, admin, etc.)
  • Estimated total tax liability (federal plus other applicable taxes you’re modeling)

If you want a fast starting point for margin math (gross and net), CannaBIZ Collects publishes a cannabis profit margin calculator. For visualizing the “280E penalty,” Wildertax offers a free interactive tool: Make It Make Sense Section 280E Calculator.

Step 2: Calculate gross profit and pre-280E gross margin

  • Gross Profit = Revenue − COGS
  • Pre-280E Gross Margin = Gross Profit ÷ Revenue

This is the cleanest view of operational efficiency before 280E distortions, as recommended by TheCannaCPAs.

Step 3: Estimate tax liability and calculate post-280E effective margin

  • Post-280E Effective Margin = (Gross Profit − Estimated Tax Liability) ÷ Revenue
  • Effective Tax Rate = (Total Tax Liability ÷ Gross Profit) × 100

This is the heart of an NJ Cannabis Profit Margin & 280E Calculator: it shows the cash margin you actually get to keep after 280E-driven taxes.

Worked example #1 (TheCannaCPAs): how “profit” can evaporate

TheCannaCPAs gives a clear illustration of 280E distortion:

  • A dispensary shows $100,000 in accounting profit after all expenses.
  • Under 280E, $80,000 of operating expenses become non-deductible.
  • That creates a tax profit of $180,000.
  • With effective tax rates often exceeding 40%, the business could owe $72,000 in taxes.
  • That leaves just $28,000 in actual cash profit despite “$100,000” in accounting profit.

This is exactly why you should calculate a post-280E effective margin, not rely on standard net margin alone.

Worked example #2 (Northstar): 280E can consume most of pre-tax income

Northstar provides a concrete dispensary example:

  • $5 million in revenue
  • 50% gross margin$2.5 million gross profit
  • $1.8 million operating expenses → $700,000 pre-tax income (14% pre-tax margin)

In normal retail, taxes would apply to the $700,000. Under 280E, Northstar notes federal taxable income becomes the full $2.5 million gross profit. At a 21% corporate tax rate, federal tax alone would be $525,000—which Northstar notes consumes 75% of the pre-tax income in that scenario, before considering state impacts.

Benchmarks to sanity-check your NJ dispensary margins and efficiency

After you calculate both pre- and post-280E margins, benchmarks help you identify whether you have a pricing problem, a COGS problem, an opex problem, or an 280E classification problem.

Gross margin: what “healthy” can look like in NJ

CannaBIZ Collects notes a healthy cannabis retail gross margin often ranges 50% to 60%. Northstar’s CFO benchmarks align with that and add NJ context: in limited-license states including New Jersey, gross margins of 52% to 60% are common due to retail pricing power.

EBITDA and after-tax expectations (when 280E planning is competent)

Northstar reports that EBITDA margins of 15% to 25% are achievable for well-run dispensaries in limited-license markets. They also state that after-tax net margins of 12% to 18% are realistic for operators with competent 280E tax planning.

Those after-tax ranges underscore why your calculator must model taxes correctly—because two dispensaries with the same gross margin can have very different after-tax outcomes depending on how much expense sits outside COGS.

Efficiency KPIs that correlate with profitability

TheCannaCPAs highlights additional KPIs that help explain why margins differ:

  • Revenue per employee: top-performing cannabis businesses generate $200,000–$400,000 in annual revenue per employee.
  • Working capital planning: cannabis businesses often require 3–6 months of operating expenses in working capital.

If your revenue per employee is underperforming while gross margin is “fine,” labor scheduling, workflow, or process design may be dragging down your post-280E effective margin.

How to improve profit margins under 280E (practical levers that show up in your calculator)

When taxes are calculated on gross profit, the most valuable improvements often come from (1) protecting gross margin, and (2) maximizing what can be legitimately treated as COGS.

Optimize COGS allocation under IRC Section 471 (often the highest-impact lever)

Northstar calls COGS allocation strategy under 280E the “highest-impact, lowest-cost” improvement available to most dispensaries, because COGS is the primary deductible category under 280E. They note the IRS permits certain indirect costs to be allocated to COGS under IRC Section 471, including portions of costs tied to procuring, securing, and maintaining inventory (for example, certain warehouse labor, storage, inventory handling, and quality inspection).

Northstar estimates that a dispensary with a supportable methodology can reduce 280E-adjusted taxable income by 10% to 25%, which can directly improve after-tax cash flow by $50,000 to $200,000+ annually for a mid-size operation.

Action step: review your chart of accounts and operational workflows to ensure every eligible inventory-related cost is consistently captured as COGS using a documented, supportable methodology.

Track cash flow from operations quarterly (not just the P&L)

TheCannaCPAs recommends tracking cash flow from operations quarterly, including the impact of inventory, accounts receivable, and payables. This matters because high effective tax rates can create sudden cash requirements even when accounting statements look stable.

Action step: add a quarterly “tax + inventory” cash planning checkpoint to your close process so you can forecast cash needs before tax deadlines hit.

Plan for 3–6 months of working capital

TheCannaCPAs notes cannabis businesses commonly need 3–6 months of operating expenses in working capital. In a high-280E environment, undercapitalization can force operational decisions (like discounting or under-ordering inventory) that lower gross margin and make the tax problem worse.

Action step: set a working-capital target in dollars (3–6 months of opex) and monitor it alongside your post-280E effective margin in the same dashboard.

Protect the margin you already have (before you try to “grow”)

Northstar’s NJ benchmark margins depend on maintaining pricing discipline. Because 280E taxes gross profit, every avoidable hit to gross margin can have an outsized impact on after-tax cash. Pair your calculator with a routine gross margin review so you can quickly spot changes in product mix, wholesale costs, shrink, or discounting.

Manage collections and cash conversion (especially if receivables are growing)

TheCannaCPAs emphasizes including receivables and payables changes in operating cash flow tracking. If accounts receivable grows while taxes are calculated on gross profit, you can end up paying taxes on profit you haven’t collected yet.

For operators that need help tightening accounts receivable processes, CannaBIZ Collects specifically highlights AR services tailored for cannabis companies on their site (a reminder that cash conversion is a margin survival skill in this industry).

Frequently Asked Questions

What is a “good” NJ dispensary profit margin after 280E?

Northstar’s CFO benchmarks for limited-license states (including New Jersey) suggest after-tax net margins of 12% to 18% are realistic for operators with competent 280E tax planning. Your NJ Cannabis Profit Margin & 280E Calculator should show whether you’re in that range by modeling taxes against gross profit (not just net income).

Why are cannabis effective tax rates so high (40% to 70% and sometimes higher)?

TheCannaCPAs reports cannabis businesses often face 40% to 70% effective tax rates versus 15% to 25% for traditional businesses, because 280E disallows many ordinary deductions. CannaBIZ Collects notes effective rates can exceed 70% in some cases, and NJ-focused guidance from TCA Advisors cites 40% to over 100% depending on margin structure.

What expenses can reduce taxable income under 280E?

Under 280E, ordinary operating expenses are generally not deductible, but COGS is central to reducing taxable income. Northstar notes that, under IRC Section 471, certain indirect costs related to procuring and maintaining inventory (such as portions of warehouse labor, storage, inventory handling, and quality inspection) may be allocated to COGS using a supportable methodology.

How often should I update my profit margin and 280E calculations?

TheCannaCPAs recommends tracking cash flow from operations quarterly to identify patterns and cash needs. Updating your margins and effective tax rate at least quarterly helps you catch changes in gross margin, inventory levels, and cash timing before they become crises.

Are there tools I can use instead of building my own calculator?

Yes. For basic profit margin math, CannaBIZ Collects provides a cannabis profit margin calculator. To visualize the 280E impact specifically, Wildertax offers a free interactive tool: Make It Make Sense Section 280E Calculator. Many operators still keep an internal spreadsheet so assumptions (like tax estimates and COGS methodology) match their actual books.

Note: This article is educational and relies on the sources cited above; work with a qualified cannabis CPA or tax professional to apply these methods to your specific facts and reporting.

Trusted by the cannabis industry since 2023

Jeeter logo
Kaviar logo
PAX logo
Rove logo
Weedmaps logo
Surfside logo
Leafly logo
eBottles logo
FundCanna logo
Headset logo
Apex Trading logo
Connected logo
Kaycha Labs logo
710 Labs logo
Ispire logo
Jeeter logo
Kaviar logo
PAX logo
Rove logo
Weedmaps logo
Surfside logo
Leafly logo
eBottles logo
FundCanna logo
Headset logo
Apex Trading logo
Connected logo
Kaycha Labs logo
710 Labs logo
Ispire logo